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 #include <hash_map> 28 #include <vector> 29 #include <string.h> 30 #include <rtl/string.h> 31 #include <rtl/strbuf.hxx> 32 #include <rtl/ustrbuf.hxx> 33 #include <osl/time.h> 34 #include "comphelper/sequence.hxx" 35 #include "ucbhelper/simplecertificatevalidationrequest.hxx" 36 37 #include "DAVAuthListener.hxx" 38 #include "CurlTypes.hxx" 39 #include "CurlSession.hxx" 40 #include "LockRequest.hxx" 41 #include "PropfindRequest.hxx" 42 #include "ProppatchRequest.hxx" 43 #include "CurlInputStream.hxx" 44 #include "UCBDeadPropertyValue.hxx" 45 #include "webdavuseragent.hxx" 46 #include "webdavresponseparser.hxx" 47 #include "webdavprovider.hxx" 48 49 50 #include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp> 51 #include <com/sun/star/logging/LogLevel.hpp> 52 #include <com/sun/star/security/XCertificate.hpp> 53 #include <com/sun/star/security/CertificateValidity.hpp> 54 #include <com/sun/star/security/CertificateContainerStatus.hpp> 55 #include <com/sun/star/security/CertificateContainer.hpp> 56 #include <com/sun/star/security/XCertificateContainer.hpp> 57 #include <com/sun/star/security/CertAltNameEntry.hpp> 58 #include <com/sun/star/security/XSanExtension.hpp> 59 #include <com/sun/star/ucb/Lock.hpp> 60 #include <com/sun/star/xml/crypto/XSEInitializer.hpp> 61 62 using namespace com::sun::star; 63 using namespace com::sun::star::logging; 64 using namespace http_dav_ucp; 65 66 #define OID_SUBJECT_ALTERNATIVE_NAME "2.5.29.17" 67 68 struct CredentialsData 69 { 70 CredentialsData( CurlSession *curlSession, CurlRequest &curlRequest, const DAVRequestEnvironment &requestEnvironment ) 71 : session( curlSession) 72 , request( curlRequest ) 73 , env( requestEnvironment ) 74 {} 75 76 CurlSession *session; 77 CurlRequest &request; 78 const DAVRequestEnvironment &env; 79 }; 80 81 // ------------------------------------------------------------------- 82 // static members! 83 CurlLockStore CurlSession::m_aCurlLockStore; 84 85 86 // ------------------------------------------------------------------- 87 // Constructor 88 // ------------------------------------------------------------------- 89 CurlSession::CurlSession( 90 const rtl::Reference< DAVSessionFactory > & rSessionFactory, 91 const rtl::OUString& inUri, 92 const ucbhelper::InternetProxyDecider & rProxyDecider ) 93 throw ( DAVException ) 94 : DAVSession( rSessionFactory ) 95 , m_aMutex() 96 , m_aContext( m_xFactory->getServiceFactory() ) 97 , m_aLogger( m_aContext.getUNOContext(), WEBDAV_CONTENT_PROVIDER_SERVICE_NAME ) 98 , m_aUri( inUri ) 99 , m_aProxyName() 100 , m_nProxyPort( 0 ) 101 , m_aServerHeaderField() 102 , m_pCurl( 0 ) 103 , m_bUseChunkedEncoding( false ) 104 , m_bTransferEncodingSwitched( false ) 105 , m_rProxyDecider( rProxyDecider ) 106 , m_aEnv() 107 { 108 m_pCurl = curl_easy_init(); 109 110 curl_easy_setopt( m_pCurl, CURLOPT_HTTPAUTH, CURLAUTH_ANY ); 111 curl_easy_setopt( m_pCurl, CURLOPT_PROXYAUTH, CURLAUTH_ANY ); 112 113 curl_easy_setopt( m_pCurl, CURLOPT_SSL_CTX_FUNCTION, Curl_SSLContextCallback ); 114 curl_easy_setopt( m_pCurl, CURLOPT_SSL_CTX_DATA, this ); 115 116 if ( m_aLogger.getLogLevel() == LogLevel::FINEST ) 117 { 118 curl_easy_setopt( m_pCurl, CURLOPT_DEBUGFUNCTION, Curl_DebugCallback ); 119 curl_easy_setopt( m_pCurl, CURLOPT_DEBUGDATA, this ); 120 curl_easy_setopt( m_pCurl, CURLOPT_VERBOSE, 1L); 121 } 122 m_aLogger.log( LogLevel::INFO, "CurlSession::CurlSession with URL $1$", 123 rtl::OUStringToOString( inUri, RTL_TEXTENCODING_UTF8 ).getStr() ); 124 } 125 126 // ------------------------------------------------------------------- 127 // Destructor 128 // ------------------------------------------------------------------- 129 CurlSession::~CurlSession( ) 130 { 131 if ( m_pCurl ) 132 { 133 curl_easy_cleanup( m_pCurl ); 134 m_pCurl = 0; 135 m_aLogger.log( LogLevel::INFO, "CurlSession::~CurlSession: closed curl session"); 136 } 137 } 138 139 // ------------------------------------------------------------------- 140 void CurlSession::Init( const DAVRequestEnvironment & rEnv ) 141 throw ( DAVException ) 142 { 143 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 144 m_aEnv = rEnv; 145 Init(); 146 } 147 148 // ------------------------------------------------------------------- 149 void CurlSession::Init() 150 throw ( DAVException ) 151 { 152 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 153 154 const sal_Char *url = rtl::OUStringToOString( m_aUri.GetURI(), RTL_TEXTENCODING_UTF8 ).getStr(); 155 CURLcode rc; 156 rc = curl_easy_setopt( m_pCurl, CURLOPT_URL, url ); 157 if ( rc != CURLE_OK ) 158 throw DAVException( DAVException::DAV_SESSION_CREATE, 159 CurlUri::makeConnectionEndPointString( m_aUri.GetHost(), m_aUri.GetPort() ) ); 160 161 const ucbhelper::InternetProxyServer & rProxyCfg = getProxySettings(); 162 if ( ( rProxyCfg.aName != m_aProxyName ) 163 || ( rProxyCfg.nPort != m_nProxyPort ) ) 164 { 165 m_aProxyName = rProxyCfg.aName; 166 m_nProxyPort = rProxyCfg.nPort; 167 if ( !m_aProxyName.isEmpty() ) 168 { 169 m_aLogger.log( LogLevel::INFO, "Using $1$ proxy server at $2$:$3$", 170 m_aUri.GetScheme(), m_aProxyName, m_nProxyPort ); 171 curl_easy_setopt( m_pCurl, CURLOPT_PROXY, rtl::OUStringToOString( m_aProxyName, RTL_TEXTENCODING_UTF8 ).getStr() ); 172 curl_easy_setopt( m_pCurl, CURLOPT_PROXYPORT, (long)m_nProxyPort ); 173 if ( m_aUri.GetScheme().equalsAscii( "https" ) ) 174 curl_easy_setopt( m_pCurl, CURLOPT_PROXYTYPE, CURLPROXY_HTTPS ); 175 else 176 curl_easy_setopt( m_pCurl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP ); 177 // no other proxy types are implemented by AOO 178 } 179 else 180 { 181 // Empty string as opposed to NULL, means don't use the default curl proxy. 182 m_aLogger.log( LogLevel::INFO, "Not using a proxy server" ); 183 curl_easy_setopt( m_pCurl, CURLOPT_PROXY, "" ); 184 } 185 // if we change the proxy settings, clear the credentials for the previous proxy too 186 curl_easy_setopt( m_pCurl, CURLOPT_PROXYUSERNAME, "" ); 187 curl_easy_setopt( m_pCurl, CURLOPT_PROXYPASSWORD, "" ); 188 } 189 } 190 191 bool CurlSession::isSSLNeeded() 192 { 193 return m_aUri.GetScheme().equalsIgnoreAsciiCase( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "https" ) ) ); 194 } 195 196 // ------------------------------------------------------------------- 197 // helper function 198 // it composes the uri for lockstore registration 199 rtl::OUString CurlSession::composeCurrentUri(const rtl::OUString & inPath) 200 { 201 rtl::OUString aScheme( m_aUri.GetScheme() ); 202 rtl::OUStringBuffer aBuf( aScheme ); 203 aBuf.appendAscii( "://" ); 204 if ( m_aUri.GetUserName().getLength() > 0 ) 205 { 206 aBuf.append( m_aUri.GetUserName() ); 207 if ( m_aUri.GetPassword().getLength() > 0 ) 208 { 209 aBuf.appendAscii( ":" ); 210 aBuf.append( m_aUri.GetPassword() ); 211 } 212 aBuf.appendAscii( "@" ); 213 } 214 // Is host a numeric IPv6 address? 215 if ( ( m_aUri.GetHost().indexOf( ':' ) != -1 ) && 216 ( m_aUri.GetHost()[ 0 ] != sal_Unicode( '[' ) ) ) 217 { 218 aBuf.appendAscii( "[" ); 219 aBuf.append( m_aUri.GetHost() ); 220 aBuf.appendAscii( "]" ); 221 } 222 else 223 { 224 aBuf.append( m_aUri.GetHost() ); 225 } 226 227 // append port, but only, if not default port. 228 bool bAppendPort = true; 229 sal_Int32 aPort = m_aUri.GetPort(); 230 switch ( aPort ) 231 { 232 case DEFAULT_HTTP_PORT: 233 bAppendPort = aScheme.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "http" ) ); 234 break; 235 236 case DEFAULT_HTTPS_PORT: 237 bAppendPort = !aScheme.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "https" ) ); 238 break; 239 } 240 if ( bAppendPort ) 241 { 242 aBuf.appendAscii( ":" ); 243 aBuf.append( rtl::OUString::valueOf( aPort ) ); 244 } 245 aBuf.append( inPath ); 246 247 rtl::OUString aUri(aBuf.makeStringAndClear() ); 248 return aUri; 249 } 250 251 // ------------------------------------------------------------------- 252 // virtual 253 sal_Bool CurlSession::CanUse( const rtl::OUString & inUri ) 254 { 255 try 256 { 257 CurlUri theUri( inUri ); 258 if ( ( theUri.GetPort() == m_aUri.GetPort() ) && 259 ( theUri.GetHost() == m_aUri.GetHost() ) && 260 ( theUri.GetScheme() == m_aUri.GetScheme() ) ) 261 { 262 return sal_True; 263 } 264 } 265 catch ( DAVException const & ) 266 { 267 return sal_False; 268 } 269 return sal_False; 270 } 271 272 // ------------------------------------------------------------------- 273 // virtual 274 sal_Bool CurlSession::UsesProxy() 275 { 276 Init(); 277 return ( m_aProxyName.getLength() > 0 ); 278 } 279 280 int CurlSession::Curl_DebugCallback( CURL *, curl_infotype type, unsigned char *data, size_t size, void* userdata ) 281 { 282 CurlSession *session = static_cast< CurlSession* >( userdata ); 283 return session->curlDebugOutput( type, reinterpret_cast<char*>( data ), size ); 284 } 285 286 int CurlSession::curlDebugOutput( curl_infotype type, char *data, int size ) 287 { 288 const char *prefix; 289 switch ( type ) 290 { 291 case CURLINFO_TEXT: 292 prefix = "[CurlINFO ]"; 293 break; 294 case CURLINFO_HEADER_IN: 295 prefix = "[CurlHDR <-]"; 296 break; 297 case CURLINFO_HEADER_OUT: 298 prefix = "[CurlHDR ->]"; 299 break; 300 case CURLINFO_DATA_IN: 301 prefix = "[CurlData<-]"; 302 break; 303 case CURLINFO_DATA_OUT: 304 prefix = "[CurlData->]"; 305 break; 306 default: 307 return 0; 308 } 309 310 // Trim the trailing \r\n 311 if ( size >= 1 && ( data[size - 1] == '\r' || data[size - 1] == '\n' ) ) 312 --size; 313 if ( size >= 1 && ( data[size - 1] == '\r' || data[size - 1] == '\n' ) ) 314 --size; 315 rtl::OString message( data, size ); 316 m_aLogger.log( LogLevel::FINEST, "$1$ $2$", prefix, message ); 317 return 0; 318 } 319 320 CURLcode CurlSession::Curl_SSLContextCallback( CURL *, void *ssl_ctx, void *userptr ) 321 { 322 CurlSession *session = static_cast<CurlSession*>( userptr ); 323 SSL_CTX *context = static_cast<SSL_CTX*>( ssl_ctx ); 324 SSL_CTX_set_app_data( context, session ); 325 SSL_CTX_set_verify( context, SSL_VERIFY_PEER, OPENSSL_ValidateServerCertificate ); 326 return CURLE_OK; 327 } 328 329 int CurlSession::OPENSSL_ValidateServerCertificate( int preverify_ok, X509_STORE_CTX *x509_ctx ) 330 { 331 SSL *ssl = static_cast<SSL*> ( 332 X509_STORE_CTX_get_ex_data( x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx() ) ); 333 SSL_CTX *ssl_ctx = SSL_get_SSL_CTX( ssl ); 334 CurlSession *session = static_cast<CurlSession*>( SSL_CTX_get_app_data( ssl_ctx ) ); 335 int verifyOk = session->validateServerX509Certificate( x509_ctx, preverify_ok ); 336 // When a certificate's verification fails within OpenSSL, yet passes from the 337 // SSL_CTX_set_verify() callback (ie. this function) (by returning 1), 338 // OpenSSL allows the connection to proceed, yet stores that last verification 339 // error and allows it to be retrieved using SSL_get_verify_result(3). 340 // 341 // Unfortunately, Curl calls SSL_get_verify_result(3) internally, and treats 342 // errors as terminal, disconnecting with an error even when we return 1 here. 343 // Therefore, to approve a certificate that OpenSSL would reject, we have to 344 // both return 1, and overwrite the X509_STORE_CTX's last error with X509_V_OK: 345 if ( verifyOk ) 346 X509_STORE_CTX_set_error( x509_ctx, X509_V_OK ); 347 return verifyOk; 348 } 349 350 static uno::Sequence< sal_Int8 > convertCertificateToAsn1Der( X509 *certificate ) 351 { 352 uno::Sequence< sal_Int8 > asn1DerCertificate; 353 int len = i2d_X509( certificate, NULL ); 354 if ( len < 0 ) 355 return asn1DerCertificate; 356 asn1DerCertificate.realloc( len ); 357 unsigned char *end = reinterpret_cast< unsigned char *>( asn1DerCertificate.getArray() ); 358 len = i2d_X509( certificate, &end ); 359 if ( len >= 0 ) 360 return asn1DerCertificate; 361 else 362 return uno::Sequence< sal_Int8 >(); 363 } 364 365 int CurlSession::validateServerX509Certificate( X509_STORE_CTX *x509StoreContext, int verifyOk ) 366 { 367 X509 *serverCertificate = X509_STORE_CTX_get_current_cert( x509StoreContext ); 368 int depth = X509_STORE_CTX_get_error_depth( x509StoreContext ); 369 STACK_OF(X509) *chain = 370 #if OPENSSL_VERSION_NUMBER >= 0x10100000L 371 X509_STORE_CTX_get0_chain( x509StoreContext ); 372 #else 373 X509_STORE_CTX_get_chain( x509StoreContext ); 374 #endif 375 376 if ( depth == 0 ) { 377 std::vector< uno::Sequence< sal_Int8 > > asn1DerCertificates; 378 if ( chain != NULL ) { 379 int nCertificates = sk_X509_num( chain ); 380 for ( int i = 0; i < nCertificates; i++ ) { 381 X509 *certificate = sk_X509_value( chain, i ); 382 uno::Sequence< sal_Int8 > asn1DerCertificate = convertCertificateToAsn1Der( certificate ); 383 if ( asn1DerCertificate.getLength() == 0 ) 384 return 0; 385 asn1DerCertificates.push_back( asn1DerCertificate ); 386 } 387 } else { 388 uno::Sequence< sal_Int8 > asn1DerCertificate = convertCertificateToAsn1Der( serverCertificate ); 389 if ( asn1DerCertificate.getLength() == 0 ) 390 return 0; 391 asn1DerCertificates.push_back( asn1DerCertificate ); 392 } 393 verifyOk = verifyCertificateChain( asn1DerCertificates ); 394 } 395 m_aLogger.log( LogLevel::FINE, "validateServerX509Certificate() returning $1$ at depth $2$", 396 (sal_Int32)verifyOk, (sal_Int32)depth ); 397 return verifyOk; 398 } 399 400 int CurlSession::verifyCertificateChain ( 401 std::vector< uno::Sequence< sal_Int8 > > &asn1DerCertificates ) 402 { 403 // Check arguments. 404 if (asn1DerCertificates.size()<=0) 405 { 406 OSL_ASSERT(asn1DerCertificates.size()>0); 407 return 0; 408 } 409 410 // Create some crypto objects to decode and handle the base64 411 // encoded certificate chain. 412 uno::Reference< xml::crypto::XSEInitializer > xSEInitializer; 413 uno::Reference< security::XCertificateContainer > xCertificateContainer; 414 uno::Reference< xml::crypto::XXMLSecurityContext > xSecurityContext; 415 uno::Reference< xml::crypto::XSecurityEnvironment > xSecurityEnv; 416 try 417 { 418 // Create a certificate container. 419 xCertificateContainer = uno::Reference< security::XCertificateContainer >( 420 getMSF()->createInstance( 421 rtl::OUString::createFromAscii( 422 "com.sun.star.security.CertificateContainer" ) ), 423 uno::UNO_QUERY_THROW); 424 425 xSEInitializer = uno::Reference< xml::crypto::XSEInitializer >( 426 getMSF()->createInstance( 427 rtl::OUString::createFromAscii( "com.sun.star.xml.crypto.SEInitializer" ) ), 428 uno::UNO_QUERY_THROW); 429 430 xSecurityContext = xSEInitializer->createSecurityContext( rtl::OUString() ); 431 if (xSecurityContext.is()) 432 xSecurityEnv = xSecurityContext->getSecurityEnvironment(); 433 434 if ( ! xSecurityContext.is() || ! xSecurityEnv.is()) 435 { 436 // Do we have to dispose xSEInitializer or xCertificateContainer? 437 m_aLogger.log( LogLevel::WARNING, "Failure creating security services for certificate verification" ); 438 return 0; 439 } 440 } 441 catch ( uno::Exception const &e) 442 { 443 m_aLogger.log( LogLevel::WARNING, "Error creating security services: $1$", e.Message ); 444 return 0; 445 } 446 447 // Decode the server certificate. 448 uno::Reference< security::XCertificate > xServerCertificate( 449 xSecurityEnv->createCertificateFromRaw( asn1DerCertificates[0] ) ); 450 if ( ! xServerCertificate.is()) 451 { 452 m_aLogger.log( LogLevel::WARNING, "Failed to create XCertificate" ); 453 return 0; 454 } 455 456 // Get the subject from the server certificate. 457 ::rtl::OUString sServerCertificateSubject (xServerCertificate->getSubjectName()); 458 sal_Int32 nIndex = 0; 459 while (nIndex >= 0) 460 { 461 const ::rtl::OUString sToken (sServerCertificateSubject.getToken(0, ',', nIndex)); 462 if (sToken.compareToAscii("CN=", 3) == 0) 463 { 464 sServerCertificateSubject = sToken.copy(3); 465 break; 466 } 467 else if (sToken.compareToAscii(" CN=", 4) == 0) 468 { 469 sServerCertificateSubject = sToken.copy(4); 470 break; 471 } 472 } 473 474 // When the certificate container already contains a (trusted) 475 // entry for the server then we do not have to authenticate any 476 // certificate. 477 const security::CertificateContainerStatus eStatus ( 478 xCertificateContainer->hasCertificate( 479 getHostName(), sServerCertificateSubject ) ); 480 if (eStatus != security::CertificateContainerStatus_NOCERT) 481 { 482 m_aLogger.log( LogLevel::FINER, "Cached certificate found with status=$1$", 483 eStatus == security::CertificateContainerStatus_TRUSTED ? "trusted" : "untrusted" ); 484 return eStatus == security::CertificateContainerStatus_TRUSTED 485 ? 1 486 : 0; 487 } 488 489 // The shortcut failed, so try to verify the whole chain. This is 490 // done outside the isDomainMatch() block because the result is 491 // used by the interaction handler. 492 std::vector< uno::Reference< security::XCertificate > > aChain; 493 for (nIndex=0; nIndex < asn1DerCertificates.size(); ++nIndex) 494 { 495 uno::Reference< security::XCertificate > xCertificate( 496 xSecurityEnv->createCertificateFromRaw( asn1DerCertificates[ nIndex ] ) ); 497 if ( ! xCertificate.is()) 498 { 499 m_aLogger.log( LogLevel::FINE, "Failed to create XCertificate $1$", nIndex ); 500 return 0; 501 } 502 aChain.push_back(xCertificate); 503 } 504 const sal_Int64 nVerificationResult (xSecurityEnv->verifyCertificate( 505 xServerCertificate, 506 ::comphelper::containerToSequence(aChain))); 507 508 // When the certificate matches the host name then we can use the 509 // result of the verification. 510 bool bHostnameMatchesCertHostnames = false; 511 { 512 uno::Sequence< uno::Reference< security::XCertificateExtension > > extensions = xServerCertificate->getExtensions(); 513 uno::Sequence< security::CertAltNameEntry > altNames; 514 for (sal_Int32 i = 0 ; i < extensions.getLength(); ++i) 515 { 516 uno::Reference< security::XCertificateExtension >element = extensions[i]; 517 518 const rtl::OString aId ( (const sal_Char *)element->getExtensionId().getArray(), element->getExtensionId().getLength()); 519 if ( aId.equals( OID_SUBJECT_ALTERNATIVE_NAME ) ) 520 { 521 uno::Reference< security::XSanExtension > sanExtension ( element, uno::UNO_QUERY ); 522 altNames = sanExtension->getAlternativeNames(); 523 break; 524 } 525 } 526 527 uno::Sequence< ::rtl::OUString > certHostNames(altNames.getLength() + 1); 528 certHostNames[0] = sServerCertificateSubject; 529 for( int n = 0; n < altNames.getLength(); ++n ) 530 { 531 if (altNames[n].Type == security::ExtAltNameType_DNS_NAME) 532 { 533 altNames[n].Value >>= certHostNames[n+1]; 534 } 535 } 536 537 for ( int i = 0; i < certHostNames.getLength() && !bHostnameMatchesCertHostnames; ++i ) 538 { 539 bHostnameMatchesCertHostnames = isDomainMatch( certHostNames[i] ); 540 } 541 542 } 543 m_aLogger.log( LogLevel::FINE, "URL hostname $1$ certificate hostname", 544 bHostnameMatchesCertHostnames ? "matches" : "DOESN'T MATCH" ); 545 if ( bHostnameMatchesCertHostnames ) 546 { 547 if (nVerificationResult == 0) 548 { 549 m_aLogger.log( LogLevel::FINE, "Certificate (chain) is valid" ); 550 xCertificateContainer->addCertificate(getHostName(), sServerCertificateSubject, sal_True); 551 return 1; 552 } 553 else if ((nVerificationResult & security::CertificateValidity::CHAIN_INCOMPLETE) != 0) 554 { 555 // We do not have enough information for verification, 556 // neither automatically (as we just discovered) nor 557 // manually (so there is no point in showing any dialog.) 558 m_aLogger.log( LogLevel::WARNING, "Certificate (chain) is incomplete" ); 559 return 0; 560 } 561 else if ((nVerificationResult & security::CertificateValidity::REVOKED) != 0) 562 { 563 // Certificate (chain) is invalid. 564 m_aLogger.log( LogLevel::WARNING, "Certificate (chain) is revoked" ); 565 xCertificateContainer->addCertificate(getHostName(), sServerCertificateSubject, sal_False); 566 return 0; 567 } 568 else 569 { 570 // For all other we have to ask the user. 571 m_aLogger.log( LogLevel::FINE, "Promping user to validate the certificate" ); 572 } 573 } 574 575 // We have not been able to automatically verify (or falsify) the 576 // certificate chain. To resolve this we have to ask the user. 577 const uno::Reference< ucb::XCommandEnvironment > xEnv( getRequestEnvironment().m_xEnv ); 578 if ( xEnv.is() ) 579 { 580 uno::Reference< task::XInteractionHandler > xIH( xEnv->getInteractionHandler() ); 581 if ( xIH.is() ) 582 { 583 rtl::Reference< ucbhelper::SimpleCertificateValidationRequest > 584 xRequest( new ucbhelper::SimpleCertificateValidationRequest( 585 static_cast<sal_Int32>(nVerificationResult), xServerCertificate, getHostName() ) ); 586 xIH->handle( xRequest.get() ); 587 588 rtl::Reference< ucbhelper::InteractionContinuation > xSelection 589 = xRequest->getSelection(); 590 591 if ( xSelection.is() ) 592 { 593 uno::Reference< task::XInteractionApprove > xApprove( xSelection.get(), uno::UNO_QUERY ); 594 if ( xApprove.is() ) 595 { 596 m_aLogger.log( LogLevel::FINE, "The user approved the certificate" ); 597 xCertificateContainer->addCertificate( getHostName(), sServerCertificateSubject, sal_True ); 598 return 1; 599 } 600 else 601 { 602 // Don't trust cert 603 m_aLogger.log( LogLevel::FINE, "The user REJECTED the certificate" ); 604 xCertificateContainer->addCertificate( getHostName(), sServerCertificateSubject, sal_False ); 605 return 0; 606 } 607 } 608 } 609 else 610 { 611 // Don't trust cert 612 m_aLogger.log( LogLevel::WARNING, "Couldn't create the interaction handler for user feedback, rejecting the certificate" ); 613 xCertificateContainer->addCertificate( getHostName(), sServerCertificateSubject, sal_False ); 614 return 0; 615 } 616 } 617 m_aLogger.log( LogLevel::WARNING, "No XCommandEnvironment, rejecting the certificate" ); 618 619 return 0; 620 } 621 622 bool CurlSession::Curl_ProvideCredentials( long statusCode, void *userdata ) throw (DAVException) 623 { 624 CredentialsData *credentialsData = (CredentialsData*)userdata; 625 return credentialsData->session->provideCredentials( credentialsData->env, credentialsData->request, statusCode ); 626 } 627 628 bool CurlSession::provideCredentials( const DAVRequestEnvironment &env, CurlRequest &request, long statusCode ) throw (DAVException) 629 { 630 DAVAuthListener * pListener = env.m_xAuthListener.get(); 631 if ( !pListener ) 632 { 633 // abort 634 m_aLogger.log( LogLevel::FINE, "No DAVAuthListener found, failing credentials entry" ); 635 return false; 636 } 637 638 rtl::OUString theUserName; 639 rtl::OUString thePassWord; 640 try 641 { 642 CurlUri uri( env.m_aRequestURI ); 643 theUserName = uri.GetUserName(); 644 thePassWord = uri.GetPassword(); 645 } 646 catch ( DAVException const &e ) 647 { 648 // abort 649 m_aLogger.log( 650 LogLevel::WARNING, 651 "Error extracing userinfo from URI: exceptionCode=$1$, status=$2$, data=$3$, owner=$4$, extendedError=$5%", 652 (sal_Int32)e.getError(), e.getStatus(), e.getData(), e.getOwner(), e.getExtendedError() 653 ); 654 return false; 655 } 656 657 bool canUseSystemCreds = false; 658 long authMethods = 0; 659 CURLcode rc = CURLE_OK; 660 if ( statusCode == 401 ) 661 rc = curl_easy_getinfo( m_pCurl, CURLINFO_HTTPAUTH_AVAIL, &authMethods ); 662 else if ( statusCode == 407 ) 663 rc = curl_easy_getinfo( m_pCurl, CURLINFO_PROXYAUTH_AVAIL, &authMethods ); 664 if ( rc == 0 ) 665 canUseSystemCreds = (authMethods & CURLAUTH_NEGOTIATE) || (authMethods & CURLAUTH_NTLM); 666 m_aLogger.log( LogLevel::FINE, "authMethods=$1$, canUseSystemCreds=$2$", 667 (sal_Int64)authMethods, (sal_Int32)canUseSystemCreds ); 668 669 const CurlRequest::Header *authHeader = NULL; 670 if ( statusCode == 401 ) 671 authHeader = request.findResponseHeader( "WWW-Authenticate" ); 672 else if ( statusCode == 407 ) 673 authHeader = request.findResponseHeader( "Proxy-Authenticate" ); 674 rtl::OUString realm; 675 if ( authHeader != NULL ) 676 { 677 int realmStart = authHeader->value.indexOf( "realm=\"" ); 678 if ( realmStart >= 0 ) 679 { 680 realmStart += 7; 681 int realmEnd = authHeader->value.indexOf( "\"", realmStart ); 682 if ( realmEnd > 0 ) 683 realm = rtl::OStringToOUString( authHeader->value.copy( realmStart, realmEnd - realmStart ), RTL_TEXTENCODING_UTF8 ); 684 } 685 } 686 687 int theRetVal = pListener->authenticate( realm, 688 getHostName(), 689 theUserName, 690 thePassWord, 691 canUseSystemCreds, 692 // Authenticating with both the proxy 693 // and the destination server requires sal_True here, 694 // and needs filling out 2 x password dialogs. 695 sal_True ); 696 697 if ( theRetVal == 0 ) 698 { 699 m_aLogger.log( LogLevel::FINEST, "got credentials for user=$1$ on realm=$2$", theUserName, realm ); 700 // "System credentials" means username and password are empty 701 const char *curlUsername = NULL; 702 const char *curlPassword = NULL; 703 if ( !theUserName.isEmpty() ) 704 curlUsername = rtl::OUStringToOString( theUserName, RTL_TEXTENCODING_UTF8 ).getStr(); 705 if ( !thePassWord.isEmpty() ) 706 curlPassword = rtl::OUStringToOString( thePassWord, RTL_TEXTENCODING_UTF8 ).getStr(); 707 if ( statusCode == 401 ) 708 { 709 curl_easy_setopt( m_pCurl, CURLOPT_USERNAME, curlUsername ); 710 curl_easy_setopt( m_pCurl, CURLOPT_PASSWORD, curlPassword ); 711 } 712 else 713 { 714 curl_easy_setopt( m_pCurl, CURLOPT_PROXYUSERNAME, curlUsername ); 715 curl_easy_setopt( m_pCurl, CURLOPT_PROXYPASSWORD, curlPassword ); 716 } 717 return true; 718 } 719 m_aLogger.log( LogLevel::WARNING, "credentials entry cancelled or failed" ); 720 721 return false; 722 } 723 724 void CurlSession::addEnvironmentRequestHeaders( CurlRequest &curlRequest, const DAVRequestEnvironment &env ) 725 throw ( DAVException ) 726 { 727 bool bHasUserAgent( false ); 728 DAVRequestHeaders::const_iterator aHeaderIter( env.m_aRequestHeaders.begin() ); 729 const DAVRequestHeaders::const_iterator aEnd( env.m_aRequestHeaders.end() ); 730 731 while ( aHeaderIter != aEnd ) 732 { 733 const rtl::OString aHeader = rtl::OUStringToOString( aHeaderIter->first, 734 RTL_TEXTENCODING_UTF8 ); 735 const rtl::OString aValue = rtl::OUStringToOString( aHeaderIter->second, 736 RTL_TEXTENCODING_UTF8 ); 737 738 if ( !bHasUserAgent ) 739 bHasUserAgent = aHeaderIter->first.equalsAsciiL( 740 RTL_CONSTASCII_STRINGPARAM( "User-Agent" ) ); 741 742 curlRequest.addHeader( aHeader, aValue ); 743 744 ++aHeaderIter; 745 } 746 747 if ( !bHasUserAgent ) 748 { 749 const rtl::OUString &rUserAgent = WebDAVUserAgent::get(); 750 curlRequest.addHeader( "User-Agent", rtl::OUStringToOString( rUserAgent, RTL_TEXTENCODING_UTF8 ) ); 751 } 752 } 753 754 void CurlSession::processResponse( CurlRequest &curlRequest, CURLcode curlCode ) 755 throw( DAVException ) 756 { 757 long statusCode = 0; 758 CURLcode curlRes; 759 curlRes = curl_easy_getinfo( m_pCurl, CURLINFO_RESPONSE_CODE, &statusCode ); 760 if ( curlRes != 0 || statusCode == 0 ) 761 statusCode = curlRequest.getStatusCode(); 762 763 // check header according: 764 // http://tools.ietf.org/html/rfc7231#section-7.4.2 765 // need to do this so we can adjust the protocol accordingly 766 const CurlRequest::Header *server = curlRequest.findResponseHeader( "server" ); 767 if ( server != NULL ) 768 m_aServerHeaderField = server->value; 769 770 if ( curlCode != 0 ) 771 { 772 m_aLogger.log( LogLevel::WARNING, "Curl request failed with CURLcode $1$", (sal_Int64)curlCode ); 773 throw DAVException( DAVException::DAV_HTTP_LOOKUP, 774 CurlUri::makeConnectionEndPointString( getHostName(), 775 getPort() ) ); 776 } 777 778 rtl::OUString reasonPhrase = rtl::OStringToOUString( curlRequest.getReasonPhrase(), RTL_TEXTENCODING_UTF8 ); 779 if ( statusCode != 0 && statusCode / 100 != 2 ) 780 { 781 switch (statusCode) 782 { 783 case SC_MOVED_PERMANENTLY: // 301 784 case SC_MOVED_TEMPORARILY: // 302 785 case SC_SEE_OTHER: // 303 786 case SC_TEMPORARY_REDIRECT: // 307 787 { 788 // new location for certain redirections 789 790 const CurlRequest::Header *location = curlRequest.findResponseHeader( "location" ); 791 if ( location != NULL ) 792 { 793 m_aLogger.log( LogLevel::FINE, "HTTP $1$ response with new location = $2$", 794 statusCode, location->value ); 795 throw DAVException( DAVException::DAV_HTTP_REDIRECT, 796 rtl::OStringToOUString( location->value, RTL_TEXTENCODING_UTF8 ) ); 797 } 798 break; 799 } 800 case SC_UNAUTHORIZED: // 401 801 case SC_PROXY_AUTHENTICATION_REQUIRED: // 407 802 { 803 throw DAVException( DAVException::DAV_HTTP_ERROR, 804 reasonPhrase, 805 statusCode ); 806 break; 807 } 808 case SC_REQUEST_ENTITY_TOO_LARGE: // 413 809 { 810 if ( m_bTransferEncodingSwitched ) 811 throw DAVException( DAVException::DAV_HTTP_ERROR, 812 reasonPhrase, 813 statusCode ); 814 m_bTransferEncodingSwitched = true; 815 curlRequest.setChunkedEncoding( !curlRequest.isChunkedEncoding() ); 816 break; 817 } 818 case SC_LOCKED: // 423 819 throw DAVException( DAVException::DAV_LOCKED, 820 reasonPhrase, 821 statusCode ); 822 default: 823 throw DAVException( DAVException::DAV_HTTP_ERROR, 824 reasonPhrase, 825 statusCode ); 826 } 827 } 828 } 829 830 static void responseHeadersToDAVResource( const std::vector< CurlRequest::Header> &responseHeaders, 831 const std::vector< ::rtl::OUString > &inHeaderNames, 832 DAVResource &ioResource ) 833 { 834 std::vector< CurlRequest::Header >::const_iterator it( responseHeaders.begin() ); 835 const std::vector< CurlRequest::Header >::const_iterator end( responseHeaders.end() ); 836 while ( it != end ) 837 { 838 bool storeHeader = false; 839 if ( inHeaderNames.size() == 0 ) 840 storeHeader = true; 841 else 842 { 843 std::vector< ::rtl::OUString >::const_iterator reqIt( inHeaderNames.begin() ); 844 const std::vector< ::rtl::OUString >::const_iterator reqEnd( inHeaderNames.end() ); 845 while ( reqIt != reqEnd ) 846 { 847 // header names are case insensitive 848 if ( (*reqIt).equalsIgnoreAsciiCase( rtl::OStringToOUString( (*it).name, RTL_TEXTENCODING_UTF8 ) ) ) 849 { 850 storeHeader = true; 851 break; 852 } 853 else 854 { 855 ++reqIt; 856 } 857 } 858 } 859 860 if ( storeHeader ) 861 { 862 DAVPropertyValue thePropertyValue; 863 thePropertyValue.IsCaseSensitive = false; 864 thePropertyValue.Name = rtl::OStringToOUString( (*it).name, RTL_TEXTENCODING_UTF8 ); 865 thePropertyValue.Value <<= rtl::OStringToOUString( (*it).value, RTL_TEXTENCODING_UTF8 ); 866 ioResource.properties.push_back( thePropertyValue ); 867 } 868 869 it++; 870 } 871 } 872 873 // ------------------------------------------------------------------- 874 // PROPFIND - allprop & named 875 // ------------------------------------------------------------------- 876 877 void CurlSession::propfind( CurlRequest &curlRequest, 878 const rtl::OUString &inPath, 879 const Depth inDepth, 880 const std::vector< ::rtl::OUString > * inPropNames, 881 const bool onlyPropertyNames, 882 const DAVRequestEnvironment & rEnv ) 883 { 884 addEnvironmentRequestHeaders( curlRequest, rEnv ); 885 886 if ( inDepth == DAVZERO ) 887 curlRequest.addHeader( "Depth", "0" ); 888 else if ( inDepth == DAVONE ) 889 curlRequest.addHeader( "Depth", "1" ); 890 else if ( inDepth == DAVINFINITY ) 891 curlRequest.addHeader( "Depth", "infinity" ); 892 893 rtl::OString xml = PropfindRequest::generatePROPFINDRequestBody( inPropNames, onlyPropertyNames ); 894 if ( xml.getLength() > 0 ) 895 { 896 curlRequest.addHeader( "Content-Type", "application/xml" ); 897 curlRequest.setRequestBody( xml.getStr(), xml.getLength() ); 898 } 899 900 CredentialsData credsData( this, curlRequest, rEnv ); 901 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 902 903 CURLcode rc = curlRequest.propfind( m_aUri, inPath ); 904 processResponse( curlRequest, rc ); 905 } 906 907 void CurlSession::PROPFIND( const rtl::OUString & inPath, 908 const Depth inDepth, 909 const std::vector< rtl::OUString > & inPropNames, 910 std::vector< DAVResource > & ioResources, 911 const DAVRequestEnvironment & rEnv ) 912 throw ( DAVException ) 913 { 914 m_aLogger.log( LogLevel::INFO, "PROPFIND line $1$", (sal_Int32)__LINE__ ); 915 916 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 917 918 Init( rEnv ); 919 CurlRequest curlRequest( m_pCurl ); 920 921 propfind( curlRequest, inPath, inDepth, &inPropNames, false, rEnv ); 922 923 const std::vector< DAVResource > rResources( parseWebDAVPropFindResponse( curlRequest.getResponseBody().get() ) ); 924 std::vector< DAVResource > *pIoResources = &ioResources; 925 *pIoResources = rResources; 926 } 927 928 // ------------------------------------------------------------------- 929 // PROPFIND - propnames 930 // ------------------------------------------------------------------- 931 void CurlSession::PROPFIND( const rtl::OUString & inPath, 932 const Depth inDepth, 933 std::vector< DAVResourceInfo > & ioResInfo, 934 const DAVRequestEnvironment & rEnv ) 935 throw( DAVException ) 936 { 937 m_aLogger.log( LogLevel::INFO, "PROPFIND line $1$", (sal_Int32)__LINE__ ); 938 939 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 940 941 Init( rEnv ); 942 CurlRequest curlRequest( m_pCurl ); 943 944 propfind( curlRequest, inPath, inDepth, NULL, true, rEnv ); 945 946 const std::vector< DAVResourceInfo > rResInfo( parseWebDAVPropNameResponse( curlRequest.getResponseBody().get() ) ); 947 std::vector< DAVResourceInfo > *pIoResInfo = &ioResInfo; 948 *pIoResInfo = rResInfo; 949 } 950 951 // ------------------------------------------------------------------- 952 // PROPPATCH 953 // ------------------------------------------------------------------- 954 void CurlSession::PROPPATCH( const rtl::OUString & inPath, 955 const std::vector< ProppatchValue > & inValues, 956 const DAVRequestEnvironment & rEnv ) 957 throw( DAVException ) 958 { 959 m_aLogger.log( LogLevel::INFO, "PROPPATCH line $1$", (sal_Int32)__LINE__ ); 960 961 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 962 963 Init( rEnv ); 964 CurlRequest curlRequest( m_pCurl ); 965 966 addEnvironmentRequestHeaders( curlRequest, rEnv ); 967 968 // check whether a lock on this resource is already owned 969 rtl::OUString aUri( composeCurrentUri( inPath ) ); 970 ucb::Lock inLock; 971 CurlLock * pLock = m_aCurlLockStore.findByUri( aUri ); 972 if ( pLock ) 973 { 974 inLock = pLock->getLock(); 975 } 976 if ( inLock.LockTokens.getLength() > 0 ) 977 { 978 curlRequest.addHeader( "If", 979 ( "(<" + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ) + ">)" ).getStr() ); 980 } 981 982 rtl::OString xml = ProppatchRequest::generatePROPPATCHRequestBody( inValues ); 983 if ( xml.getLength() > 0 ) 984 { 985 curlRequest.addHeader( "Content-Type", "application/xml" ); 986 curlRequest.setRequestBody( xml.getStr(), xml.getLength() ); 987 } 988 989 CredentialsData credsData( this, curlRequest, rEnv ); 990 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 991 992 CURLcode rc = curlRequest.proppatch( m_aUri, inPath ); 993 processResponse( curlRequest, rc ); 994 } 995 996 // ------------------------------------------------------------------- 997 // HEAD 998 // ------------------------------------------------------------------- 999 void CurlSession::HEAD( const ::rtl::OUString & inPath, 1000 const std::vector< ::rtl::OUString > & inHeaderNames, 1001 DAVResource & ioResource, 1002 const DAVRequestEnvironment & rEnv ) 1003 throw( DAVException ) 1004 { 1005 m_aLogger.log( LogLevel::INFO, "HEAD line $1$", (sal_Int32)__LINE__ ); 1006 1007 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1008 1009 Init(rEnv ); 1010 CurlRequest curlRequest( m_pCurl ); 1011 1012 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1013 1014 ioResource.uri = inPath; 1015 ioResource.properties.clear(); 1016 1017 CredentialsData credsData( this, curlRequest, rEnv ); 1018 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1019 1020 CURLcode rc = curlRequest.head( m_aUri, inPath ); 1021 processResponse( curlRequest, rc ); 1022 responseHeadersToDAVResource( curlRequest.getResponseHeaders(), inHeaderNames, ioResource ); 1023 } 1024 1025 // ------------------------------------------------------------------- 1026 // GET 1027 // ------------------------------------------------------------------- 1028 uno::Reference< io::XInputStream > 1029 CurlSession::GET( const rtl::OUString & inPath, 1030 const DAVRequestEnvironment & rEnv ) 1031 throw ( DAVException ) 1032 { 1033 m_aLogger.log( LogLevel::INFO, "GET line $1$", (sal_Int32)__LINE__ ); 1034 1035 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1036 1037 Init( rEnv ); 1038 CurlRequest curlRequest( m_pCurl ); 1039 1040 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1041 1042 CredentialsData credsData( this, curlRequest, rEnv ); 1043 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1044 1045 CURLcode rc = curlRequest.get( m_aUri, inPath ); 1046 processResponse( curlRequest, rc ); 1047 1048 return uno::Reference< io::XInputStream >( curlRequest.getResponseBody().get() ); 1049 } 1050 1051 // ------------------------------------------------------------------- 1052 // GET 1053 // ------------------------------------------------------------------- 1054 void CurlSession::GET( const rtl::OUString & inPath, 1055 uno::Reference< io::XOutputStream > & ioOutputStream, 1056 const DAVRequestEnvironment & rEnv ) 1057 throw ( DAVException ) 1058 { 1059 m_aLogger.log( LogLevel::INFO, "GET line $1$", (sal_Int32)__LINE__ ); 1060 1061 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1062 1063 Init( rEnv ); 1064 CurlRequest curlRequest( m_pCurl ); 1065 1066 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1067 1068 CredentialsData credsData( this, curlRequest, rEnv ); 1069 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1070 1071 curlRequest.saveResponseBodyTo( ioOutputStream ); 1072 CURLcode rc = curlRequest.get( m_aUri, inPath ); 1073 processResponse( curlRequest, rc ); 1074 } 1075 1076 // ------------------------------------------------------------------- 1077 // GET 1078 // ------------------------------------------------------------------- 1079 uno::Reference< io::XInputStream > 1080 CurlSession::GET( const rtl::OUString & inPath, 1081 const std::vector< ::rtl::OUString > & inHeaderNames, 1082 DAVResource & ioResource, 1083 const DAVRequestEnvironment & rEnv ) 1084 throw ( DAVException ) 1085 { 1086 m_aLogger.log( LogLevel::INFO, "GET line $1$", (sal_Int32)__LINE__ ); 1087 1088 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1089 1090 Init( rEnv ); 1091 CurlRequest curlRequest( m_pCurl ); 1092 1093 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1094 1095 CredentialsData credsData( this, curlRequest, rEnv ); 1096 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1097 1098 CURLcode rc = curlRequest.get( m_aUri, inPath ); 1099 processResponse( curlRequest, rc ); 1100 responseHeadersToDAVResource( curlRequest.getResponseHeaders(), inHeaderNames, ioResource ); 1101 1102 return uno::Reference< io::XInputStream >( curlRequest.getResponseBody().get() ); 1103 } 1104 1105 1106 // ------------------------------------------------------------------- 1107 // GET 1108 // ------------------------------------------------------------------- 1109 void CurlSession::GET( const rtl::OUString & inPath, 1110 uno::Reference< io::XOutputStream > & ioOutputStream, 1111 const std::vector< ::rtl::OUString > & inHeaderNames, 1112 DAVResource & ioResource, 1113 const DAVRequestEnvironment & rEnv ) 1114 throw ( DAVException ) 1115 { 1116 m_aLogger.log( LogLevel::INFO, "GET line $1$", (sal_Int32)__LINE__ ); 1117 1118 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1119 1120 Init( rEnv ); 1121 CurlRequest curlRequest( m_pCurl ); 1122 1123 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1124 1125 CredentialsData credsData( this, curlRequest, rEnv ); 1126 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1127 1128 curlRequest.saveResponseBodyTo( ioOutputStream ); 1129 CURLcode rc = curlRequest.get( m_aUri, inPath ); 1130 processResponse( curlRequest, rc ); 1131 responseHeadersToDAVResource( curlRequest.getResponseHeaders(), inHeaderNames, ioResource ); 1132 } 1133 1134 // ------------------------------------------------------------------- 1135 // PUT 1136 // ------------------------------------------------------------------- 1137 void CurlSession::PUT( const rtl::OUString & inPath, 1138 const uno::Reference< io::XInputStream > & inInputStream, 1139 const DAVRequestEnvironment & rEnv ) 1140 throw ( DAVException ) 1141 { 1142 m_aLogger.log( LogLevel::INFO, "PUT line $1$", (sal_Int32)__LINE__ ); 1143 1144 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1145 1146 Init( rEnv ); 1147 CurlRequest curlRequest( m_pCurl ); 1148 1149 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1150 1151 uno::Sequence< sal_Int8 > aDataToSend; 1152 if ( !getDataFromInputStream( inInputStream, aDataToSend, false ) ) 1153 throw DAVException( DAVException::DAV_INVALID_ARG ); 1154 curlRequest.setRequestBody( reinterpret_cast< const char * >( aDataToSend.getConstArray() ), 1155 aDataToSend.getLength() ); 1156 1157 CredentialsData credsData( this, curlRequest, rEnv ); 1158 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1159 1160 // check whether a lock on this resource is already owned 1161 rtl::OUString aUri( composeCurrentUri( inPath ) ); 1162 ucb::Lock inLock; 1163 CurlLock * pLock = m_aCurlLockStore.findByUri( aUri ); 1164 if ( pLock ) 1165 { 1166 inLock = pLock->getLock(); 1167 } 1168 if ( inLock.LockTokens.getLength() > 0 ) 1169 { 1170 curlRequest.addHeader( "If", 1171 ( "(<" + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ) + ">)" ).getStr() ); 1172 } 1173 1174 CURLcode rc = curlRequest.put( m_aUri, inPath ); 1175 processResponse( curlRequest, rc ); 1176 } 1177 1178 // ------------------------------------------------------------------- 1179 // POST 1180 // ------------------------------------------------------------------- 1181 uno::Reference< io::XInputStream > 1182 CurlSession::POST( const rtl::OUString & inPath, 1183 const rtl::OUString & rContentType, 1184 const rtl::OUString & rReferer, 1185 const uno::Reference< io::XInputStream > & inInputStream, 1186 const DAVRequestEnvironment & rEnv ) 1187 throw ( DAVException ) 1188 { 1189 m_aLogger.log( LogLevel::INFO, "POST line $1$", (sal_Int32)__LINE__ ); 1190 1191 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1192 1193 Init( rEnv ); 1194 CurlRequest curlRequest( m_pCurl ); 1195 1196 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1197 1198 uno::Sequence< sal_Int8 > aDataToSend; 1199 if ( !getDataFromInputStream( inInputStream, aDataToSend, false ) ) 1200 throw DAVException( DAVException::DAV_INVALID_ARG ); 1201 curlRequest.setRequestBody( reinterpret_cast< const char * >( aDataToSend.getConstArray() ), 1202 aDataToSend.getLength() ); 1203 1204 CredentialsData credsData( this, curlRequest, rEnv ); 1205 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1206 1207 if ( !rContentType.isEmpty() ) 1208 curlRequest.addHeader( "Content-Type", rtl::OUStringToOString( rContentType, RTL_TEXTENCODING_UTF8 ).getStr() ); 1209 if ( !rReferer.isEmpty() ) 1210 curlRequest.addHeader( "Referer", rtl::OUStringToOString( rReferer, RTL_TEXTENCODING_UTF8 ).getStr() ); 1211 1212 // check whether a lock on this resource is already owned 1213 rtl::OUString aUri( composeCurrentUri( inPath ) ); 1214 ucb::Lock inLock; 1215 CurlLock * pLock = m_aCurlLockStore.findByUri( aUri ); 1216 if ( pLock ) 1217 { 1218 inLock = pLock->getLock(); 1219 } 1220 if ( inLock.LockTokens.getLength() > 0 ) 1221 { 1222 curlRequest.addHeader( "If", 1223 ( "(<" + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ) + ">)" ).getStr() ); 1224 } 1225 1226 CURLcode rc = curlRequest.post( m_aUri, inPath ); 1227 processResponse( curlRequest, rc ); 1228 return uno::Reference< io::XInputStream >( curlRequest.getResponseBody().get() ); 1229 } 1230 1231 // ------------------------------------------------------------------- 1232 // POST 1233 // ------------------------------------------------------------------- 1234 void CurlSession::POST( const rtl::OUString & inPath, 1235 const rtl::OUString & rContentType, 1236 const rtl::OUString & rReferer, 1237 const uno::Reference< io::XInputStream > & inInputStream, 1238 uno::Reference< io::XOutputStream > & oOutputStream, 1239 const DAVRequestEnvironment & rEnv ) 1240 throw ( DAVException ) 1241 { 1242 m_aLogger.log( LogLevel::INFO, "POST line $1$", (sal_Int32)__LINE__ ); 1243 1244 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1245 1246 Init( rEnv ); 1247 CurlRequest curlRequest( m_pCurl ); 1248 1249 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1250 1251 uno::Sequence< sal_Int8 > aDataToSend; 1252 if ( !getDataFromInputStream( inInputStream, aDataToSend, false ) ) 1253 throw DAVException( DAVException::DAV_INVALID_ARG ); 1254 curlRequest.setRequestBody( reinterpret_cast< const char * >( aDataToSend.getConstArray() ), 1255 aDataToSend.getLength() ); 1256 1257 CredentialsData credsData( this, curlRequest, rEnv ); 1258 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1259 1260 if ( !rContentType.isEmpty() ) 1261 curlRequest.addHeader( "Content-Type", rtl::OUStringToOString( rContentType, RTL_TEXTENCODING_UTF8 ).getStr() ); 1262 if ( !rReferer.isEmpty() ) 1263 curlRequest.addHeader( "Referer", rtl::OUStringToOString( rReferer, RTL_TEXTENCODING_UTF8 ).getStr() ); 1264 1265 // check whether a lock on this resource is already owned 1266 rtl::OUString aUri( composeCurrentUri( inPath ) ); 1267 ucb::Lock inLock; 1268 CurlLock * pLock = m_aCurlLockStore.findByUri( aUri ); 1269 if ( pLock ) 1270 { 1271 inLock = pLock->getLock(); 1272 } 1273 if ( inLock.LockTokens.getLength() > 0 ) 1274 { 1275 curlRequest.addHeader( "If", 1276 ( "(<" + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ) + ">)" ).getStr() ); 1277 } 1278 1279 curlRequest.saveResponseBodyTo( oOutputStream ); 1280 CURLcode rc = curlRequest.post( m_aUri, inPath ); 1281 processResponse( curlRequest, rc ); 1282 } 1283 1284 // ------------------------------------------------------------------- 1285 // MKCOL 1286 // ------------------------------------------------------------------- 1287 void CurlSession::MKCOL( const rtl::OUString & inPath, 1288 const DAVRequestEnvironment & rEnv ) 1289 throw ( DAVException ) 1290 { 1291 m_aLogger.log( LogLevel::INFO, "MKCOL line $1$", (sal_Int32)__LINE__ ); 1292 1293 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1294 1295 Init( rEnv ); 1296 CurlRequest curlRequest( m_pCurl ); 1297 1298 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1299 1300 CredentialsData credsData( this, curlRequest, rEnv ); 1301 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1302 1303 // check whether a lock on this resource is already owned 1304 rtl::OUString aUri( composeCurrentUri( inPath ) ); 1305 ucb::Lock inLock; 1306 CurlLock * pLock = m_aCurlLockStore.findByUri( aUri ); 1307 if ( pLock ) 1308 { 1309 inLock = pLock->getLock(); 1310 } 1311 if ( inLock.LockTokens.getLength() > 0 ) 1312 { 1313 curlRequest.addHeader( "If", 1314 ( "(<" + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ) + ">)" ).getStr() ); 1315 } 1316 1317 CURLcode rc = curlRequest.mkcol( m_aUri, inPath ); 1318 processResponse( curlRequest, rc ); 1319 } 1320 1321 // ------------------------------------------------------------------- 1322 // COPY 1323 // ------------------------------------------------------------------- 1324 void CurlSession::COPY( const rtl::OUString & inSourceURL, 1325 const rtl::OUString & inDestinationURL, 1326 const DAVRequestEnvironment & rEnv, 1327 sal_Bool inOverWrite ) 1328 throw ( DAVException ) 1329 { 1330 m_aLogger.log( LogLevel::INFO, "COPY line $1$", (sal_Int32)__LINE__ ); 1331 1332 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1333 1334 Init( rEnv ); 1335 CurlRequest curlRequest( m_pCurl ); 1336 1337 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1338 1339 CredentialsData credsData( this, curlRequest, rEnv ); 1340 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1341 1342 curlRequest.addHeader( "Destination", rtl::OUStringToOString( inDestinationURL, RTL_TEXTENCODING_UTF8 ).getStr() ); 1343 curlRequest.addHeader( "Overwrite", inOverWrite? "T" : "F" ); 1344 1345 // check whether a lock on the destination resource is already owned 1346 rtl::OUString aUri( composeCurrentUri( inDestinationURL ) ); 1347 ucb::Lock inLock; 1348 CurlLock * pLock = m_aCurlLockStore.findByUri( aUri ); 1349 if ( pLock ) 1350 { 1351 inLock = pLock->getLock(); 1352 } 1353 if ( inLock.LockTokens.getLength() > 0 ) 1354 { 1355 curlRequest.addHeader( "If", 1356 ( "(<" + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ) + ">)" ).getStr() ); 1357 } 1358 1359 CURLcode rc = curlRequest.copy( m_aUri, CurlUri( inSourceURL ).GetPath() ); 1360 processResponse( curlRequest, rc ); 1361 } 1362 1363 // ------------------------------------------------------------------- 1364 // MOVE 1365 // ------------------------------------------------------------------- 1366 void CurlSession::MOVE( const rtl::OUString & inSourceURL, 1367 const rtl::OUString & inDestinationURL, 1368 const DAVRequestEnvironment & rEnv, 1369 sal_Bool inOverWrite ) 1370 throw ( DAVException ) 1371 { 1372 m_aLogger.log( LogLevel::INFO, "MOVE line $1$", (sal_Int32)__LINE__ ); 1373 1374 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1375 1376 Init( rEnv ); 1377 CurlRequest curlRequest( m_pCurl ); 1378 1379 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1380 1381 CredentialsData credsData( this, curlRequest, rEnv ); 1382 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1383 1384 curlRequest.addHeader( "Destination", rtl::OUStringToOString( inDestinationURL, RTL_TEXTENCODING_UTF8 ).getStr() ); 1385 curlRequest.addHeader( "Overwrite", inOverWrite? "T" : "F" ); 1386 1387 // check whether a lock on the destination resource is already owned 1388 rtl::OUString aUri( composeCurrentUri( inDestinationURL ) ); 1389 ucb::Lock inLock; 1390 CurlLock * pLock = m_aCurlLockStore.findByUri( aUri ); 1391 if ( pLock ) 1392 { 1393 inLock = pLock->getLock(); 1394 } 1395 if ( inLock.LockTokens.getLength() > 0 ) 1396 { 1397 curlRequest.addHeader( "If", 1398 ( "(<" + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ) + ">)" ).getStr() ); 1399 } 1400 1401 CURLcode rc = curlRequest.copy( m_aUri, CurlUri( inSourceURL ).GetPath() ); 1402 processResponse( curlRequest, rc ); 1403 } 1404 1405 // ------------------------------------------------------------------- 1406 // DESTROY 1407 // ------------------------------------------------------------------- 1408 void CurlSession::DESTROY( const rtl::OUString & inPath, 1409 const DAVRequestEnvironment & rEnv ) 1410 throw ( DAVException ) 1411 { 1412 m_aLogger.log( LogLevel::INFO, "DESTROY line $1$", (sal_Int32)__LINE__ ); 1413 1414 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1415 1416 Init( rEnv ); 1417 CurlRequest curlRequest( m_pCurl ); 1418 1419 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1420 1421 CredentialsData credsData( this, curlRequest, rEnv ); 1422 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1423 1424 // check whether a lock on this resource is already owned 1425 rtl::OUString aUri( composeCurrentUri( inPath ) ); 1426 ucb::Lock inLock; 1427 CurlLock * pLock = m_aCurlLockStore.findByUri( aUri ); 1428 if ( pLock ) 1429 { 1430 inLock = pLock->getLock(); 1431 } 1432 if ( inLock.LockTokens.getLength() > 0 ) 1433 { 1434 curlRequest.addHeader( "If", 1435 ( "(<" + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ) + ">)" ).getStr() ); 1436 } 1437 1438 CURLcode rc = curlRequest.delete_( m_aUri, inPath ); 1439 processResponse( curlRequest, rc ); 1440 } 1441 1442 // ------------------------------------------------------------------- 1443 1444 namespace 1445 { 1446 sal_Int32 lastChanceToSendRefreshRequest( TimeValue const & rStart, 1447 sal_Int32 timeout ) 1448 { 1449 TimeValue aEnd; 1450 osl_getSystemTime( &aEnd ); 1451 1452 // Try to estimate a safe absolute time for sending the 1453 // lock refresh request. 1454 sal_Int32 lastChanceToSendRefreshRequest = DAVINFINITY; 1455 if ( timeout != DAVINFINITY ) 1456 { 1457 sal_Int32 calltime = aEnd.Seconds - rStart.Seconds; 1458 if ( calltime <= timeout ) 1459 { 1460 lastChanceToSendRefreshRequest 1461 = aEnd.Seconds + timeout - calltime; 1462 } 1463 else 1464 { 1465 OSL_TRACE( "No chance to refresh lock before timeout!" ); 1466 } 1467 } 1468 return lastChanceToSendRefreshRequest; 1469 } 1470 1471 } // namespace 1472 1473 // ------------------------------------------------------------------- 1474 // LOCK (set new lock) 1475 // ------------------------------------------------------------------- 1476 void CurlSession::LOCK( const ::rtl::OUString & inPath, 1477 ucb::Lock & inLock, 1478 const DAVRequestEnvironment & rEnv ) 1479 throw ( DAVException ) 1480 { 1481 m_aLogger.log( LogLevel::INFO, "LOCK line $1$", (sal_Int32)__LINE__ ); 1482 1483 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1484 1485 // before locking, search in the lock store if we already own a lock for this resource 1486 // if present, return with exception DAV_LOCKED_SELF 1487 rtl::OUString aUri( composeCurrentUri( inPath ) ); 1488 CurlLock * pLock = m_aCurlLockStore.findByUri( aUri ); 1489 if ( pLock ) 1490 { 1491 // already present, meaning already locked by the same AOO session and already in the lockstore 1492 // just return, nothing to do 1493 return; 1494 } 1495 1496 Init( rEnv ); 1497 CurlRequest curlRequest( m_pCurl ); 1498 1499 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1500 1501 CredentialsData credsData( this, curlRequest, rEnv ); 1502 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1503 1504 if ( inLock.Timeout == -1 ) 1505 curlRequest.addHeader( "Timeout", "Infinite" ); 1506 else 1507 curlRequest.addHeader( "Timeout", "Second-" + rtl::OString::valueOf( inLock.Timeout ) ); 1508 1509 switch ( inLock.Depth ) 1510 { 1511 //i126305 TODO investigate on this case... 1512 case ucb::LockDepth_MAKE_FIXED_SIZE: 1513 1514 case ucb::LockDepth_ZERO: 1515 curlRequest.addHeader( "Depth", "0" ); 1516 break; 1517 case ucb::LockDepth_ONE: 1518 curlRequest.addHeader( "Depth", "1" ); 1519 break; 1520 case ucb::LockDepth_INFINITY: 1521 curlRequest.addHeader( "Depth", "infinity" ); 1522 break; 1523 } 1524 1525 rtl::OString xml = LockRequest::generateRequestBody( inLock ); 1526 curlRequest.addHeader( "Content-Type", "application/xml" ); 1527 curlRequest.setRequestBody( xml.getStr(), xml.getLength() ); 1528 1529 TimeValue startCall; 1530 osl_getSystemTime( &startCall ); 1531 1532 CURLcode rc = curlRequest.lock( m_aUri, inPath ); 1533 processResponse( curlRequest, rc ); 1534 1535 // the returned property, a sequence of locks 1536 // only the first is used 1537 const DAVPropertyValue outLock( parseWebDAVLockResponse( curlRequest.getResponseBody().get() ) ); 1538 if(outLock.Name.compareToAscii(RTL_CONSTASCII_STRINGPARAM( "DAV:lockdiscovery" )) == 0 ) 1539 { 1540 // got a lock, use only the first returned 1541 uno::Sequence< ucb::Lock > aLocks; 1542 outLock.Value >>= aLocks; 1543 ucb::Lock aLock = aLocks[0]; 1544 1545 CurlLock* aNewLock = new CurlLock( aLock, aUri, inPath ); 1546 // add the store the new lock 1547 m_aCurlLockStore.addLock(aNewLock,this, 1548 lastChanceToSendRefreshRequest( 1549 startCall, static_cast< sal_Int32 >(aLock.Timeout) ) ); 1550 } 1551 } 1552 1553 // ------------------------------------------------------------------- 1554 // LOCK (refresh existing lock from DAVResourceAccess) 1555 // ------------------------------------------------------------------- 1556 sal_Int64 CurlSession::LOCK( const ::rtl::OUString & /*inPath*/, 1557 sal_Int64 nTimeout, 1558 const DAVRequestEnvironment & /*rEnv*/ ) 1559 throw ( DAVException ) 1560 { 1561 m_aLogger.log( LogLevel::INFO, "LOCK line $1$", (sal_Int32)__LINE__ ); 1562 1563 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1564 1565 return nTimeout; 1566 /* 1567 // Try to get the neon lock from lock store 1568 CurlLock * theLock 1569 = m_aCurlLockStore.findByUri( makeAbsoluteURL( inPath ) ); 1570 if ( !theLock ) 1571 throw DAVException( DAVException::DAV_NOT_LOCKED ); 1572 1573 Init( rEnv ); 1574 1575 // refresh existing lock. 1576 theLock->timeout = static_cast< long >( nTimeout ); 1577 1578 TimeValue startCall; 1579 osl_getSystemTime( &startCall ); 1580 1581 int theRetVal = ne_lock_refresh( m_pHttpSession, theLock ); 1582 1583 if ( theRetVal == NE_OK ) 1584 { 1585 m_aCurlLockStore.updateLock( theLock, 1586 lastChanceToSendRefreshRequest( 1587 startCall, theLock->timeout ) ); 1588 } 1589 1590 HandleError( theRetVal, inPath, rEnv ); 1591 1592 return theLock->timeout; 1593 */ 1594 } 1595 1596 // ------------------------------------------------------------------- 1597 // LOCK (refresh existing lock from CurlLockStore) 1598 // ------------------------------------------------------------------- 1599 bool CurlSession::LOCK( CurlLock * pLock, 1600 sal_Int32 & rlastChanceToSendRefreshRequest ) 1601 { 1602 m_aLogger.log( LogLevel::INFO, "LOCK line $1$", (sal_Int32)__LINE__ ); 1603 1604 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1605 1606 Init(); 1607 CurlRequest curlRequest( m_pCurl ); 1608 1609 const ucb::Lock & inLock = pLock->getLock(); 1610 rtl::OUString inPath = pLock->getResourcePath(); 1611 1612 if ( inLock.Timeout == -1 ) 1613 curlRequest.addHeader( "Timeout", "Infinite" ); 1614 else 1615 curlRequest.addHeader( "Timeout", "Second-" + rtl::OString::valueOf( inLock.Timeout ) ); 1616 1617 switch ( inLock.Depth ) 1618 { 1619 //i126305 TODO investigate on this case... 1620 case ucb::LockDepth_MAKE_FIXED_SIZE: 1621 1622 case ucb::LockDepth_ZERO: 1623 curlRequest.addHeader( "Depth", "0" ); 1624 break; 1625 case ucb::LockDepth_ONE: 1626 curlRequest.addHeader( "Depth", "1" ); 1627 break; 1628 case ucb::LockDepth_INFINITY: 1629 curlRequest.addHeader( "Depth", "infinity" ); 1630 break; 1631 } 1632 1633 if ( inLock.LockTokens.getLength() > 0 ) 1634 { 1635 curlRequest.addHeader( "If", 1636 ( "(<" + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ) + ">)" ).getStr() ); 1637 } 1638 1639 rtl::OString xml = LockRequest::generateRequestBody( inLock ); 1640 curlRequest.addHeader( "Content-Type", "application/xml" ); 1641 curlRequest.setRequestBody( xml.getStr(), xml.getLength() ); 1642 1643 TimeValue startCall; 1644 osl_getSystemTime( &startCall ); 1645 1646 CURLcode rc = curlRequest.lock( m_aUri, inPath ); 1647 processResponse( curlRequest, rc ); 1648 1649 // the returned property, a sequence of locks 1650 // only the first is used 1651 const DAVPropertyValue outLock( parseWebDAVLockResponse( curlRequest.getResponseBody().get() ) ); 1652 uno::Sequence< ucb::Lock > aLocks; 1653 outLock.Value >>= aLocks; 1654 ucb::Lock aLock = aLocks[0]; 1655 1656 // if ok, update the lastchance refresh time in lock 1657 rlastChanceToSendRefreshRequest 1658 = lastChanceToSendRefreshRequest( startCall, static_cast< sal_Int32 >(aLock.Timeout) ); 1659 1660 return true; 1661 } 1662 1663 // ------------------------------------------------------------------- 1664 // UNLOCK called from external (DAVResourceAccess) 1665 // ------------------------------------------------------------------- 1666 void CurlSession::UNLOCK( const ::rtl::OUString & inPath, 1667 const DAVRequestEnvironment & rEnv ) 1668 throw ( DAVException ) 1669 { 1670 m_aLogger.log( LogLevel::INFO, "UNLOCK line $1$", (sal_Int32)__LINE__ ); 1671 1672 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1673 1674 rtl::OUString aUri( composeCurrentUri( inPath ) ); 1675 CurlLock * pLock = m_aCurlLockStore.findByUri( aUri ); 1676 if ( !pLock ) 1677 { 1678 throw DAVException( DAVException::DAV_NOT_LOCKED ); 1679 } 1680 1681 Init( rEnv ); 1682 CurlRequest curlRequest( m_pCurl ); 1683 1684 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1685 1686 CredentialsData credsData( this, curlRequest, rEnv ); 1687 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1688 1689 ucb::Lock inLock = pLock->getLock(); 1690 curlRequest.addHeader( "Lock-Token", 1691 ( "<" + rtl::OUStringToOString( inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ) + ">" ).getStr() ); 1692 1693 // remove lock from lockstore 1694 // so, if something goes wrong, we don't refresh it anymore 1695 m_aCurlLockStore.removeLock( pLock ); 1696 delete pLock; 1697 1698 CURLcode rc = curlRequest.unlock( m_aUri, inPath ); 1699 processResponse( curlRequest, rc ); 1700 } 1701 1702 // ------------------------------------------------------------------- 1703 // UNLOCK (called from CurlLockStore) 1704 // ------------------------------------------------------------------- 1705 bool CurlSession::UNLOCK( CurlLock * pLock ) 1706 { 1707 m_aLogger.log( LogLevel::INFO, "UNLOCK line $1$", (sal_Int32)__LINE__ ); 1708 1709 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1710 1711 Init(); 1712 CurlRequest curlRequest( m_pCurl ); 1713 1714 rtl::OUString inPath = pLock->getResourcePath(); 1715 ucb::Lock inLock = pLock->getLock(); 1716 curlRequest.addHeader( "Lock-Token", 1717 ( "<" + rtl::OUStringToOString( inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ) + ">" ).getStr() ); 1718 1719 CURLcode rc = curlRequest.unlock( m_aUri, inPath ); 1720 processResponse( curlRequest, rc ); 1721 return true; 1722 } 1723 1724 // ------------------------------------------------------------------- 1725 void CurlSession::abort() 1726 throw ( DAVException ) 1727 { 1728 // 11.11.09 (tkr): The following code lines causing crashes if 1729 // closing a ongoing connection. It turned out that this existing 1730 // solution doesn't work in multi-threading environments. 1731 // So I disabled them in 3.2. . Issue #73893# should fix it in OOo 3.3. 1732 //if ( m_pHttpSession ) 1733 // ne_close_connection( m_pHttpSession ); 1734 } 1735 1736 // ------------------------------------------------------------------- 1737 const ucbhelper::InternetProxyServer & CurlSession::getProxySettings() const 1738 { 1739 if ( m_aUri.GetScheme().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "http" ) ) || 1740 m_aUri.GetScheme().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "https" ) ) ) 1741 { 1742 return m_rProxyDecider.getProxy( m_aUri.GetScheme(), 1743 m_aUri.GetHost(), 1744 m_aUri.GetPort() ); 1745 } 1746 else 1747 { 1748 // TODO: figure out, if this case can occur 1749 return m_rProxyDecider.getProxy( m_aUri.GetScheme(), 1750 rtl::OUString() /* not used */, 1751 -1 /* not used */ ); 1752 } 1753 } 1754 1755 /* 1756 // ------------------------------------------------------------------- 1757 namespace { 1758 1759 bool containsLocktoken( const uno::Sequence< ucb::Lock > & rLocks, 1760 const char * token ) 1761 { 1762 for ( sal_Int32 n = 0; n < rLocks.getLength(); ++n ) 1763 { 1764 const uno::Sequence< rtl::OUString > & rTokens 1765 = rLocks[ n ].LockTokens; 1766 for ( sal_Int32 m = 0; m < rTokens.getLength(); ++m ) 1767 { 1768 if ( rTokens[ m ].equalsAscii( token ) ) 1769 return true; 1770 } 1771 } 1772 return false; 1773 } 1774 1775 } // namespace 1776 */ 1777 1778 // ------------------------------------------------------------------- 1779 // This method doesn't seem to be used. 1780 // In any case the default behavior is to ask a lock with a life of 3 minutes 1781 // it will then be refreshed automatically (see CurlLockStore class) 1782 // In case of AOO crash the lock will expire by itself 1783 bool CurlSession::removeExpiredLocktoken( const rtl::OUString & /*inURL*/, 1784 const DAVRequestEnvironment & /*rEnv*/ ) 1785 { 1786 return true; 1787 /* 1788 CurlLock * theLock = m_aCurlLockStore.findByUri( inURL ); 1789 if ( !theLock ) 1790 return false; 1791 1792 // do a lockdiscovery to check whether this lock is still valid. 1793 try 1794 { 1795 // @@@ Alternative: use ne_lock_discover() => less overhead 1796 1797 std::vector< DAVResource > aResources; 1798 std::vector< rtl::OUString > aPropNames; 1799 aPropNames.push_back( DAVProperties::LOCKDISCOVERY ); 1800 1801 PROPFIND( rEnv.m_aRequestURI, DAVZERO, aPropNames, aResources, rEnv ); 1802 1803 if ( aResources.size() == 0 ) 1804 return false; 1805 1806 std::vector< DAVPropertyValue >::const_iterator it 1807 = aResources[ 0 ].properties.begin(); 1808 std::vector< DAVPropertyValue >::const_iterator end 1809 = aResources[ 0 ].properties.end(); 1810 1811 while ( it != end ) 1812 { 1813 if ( (*it).Name.equals( DAVProperties::LOCKDISCOVERY ) ) 1814 { 1815 uno::Sequence< ucb::Lock > aLocks; 1816 if ( !( (*it).Value >>= aLocks ) ) 1817 return false; 1818 1819 if ( !containsLocktoken( aLocks, theLock->token ) ) 1820 { 1821 // expired! 1822 break; 1823 } 1824 1825 // still valid. 1826 return false; 1827 } 1828 ++it; 1829 } 1830 1831 // No lockdiscovery prop in propfind result / locktoken not found 1832 // in propfind result -> not locked 1833 OSL_TRACE( "CurlSession::removeExpiredLocktoken: Removing " 1834 " expired lock token for %s. token: %s", 1835 rtl::OUStringToOString( inURL, 1836 RTL_TEXTENCODING_UTF8 ).getStr(), 1837 theLock->token ); 1838 1839 m_aCurlLockStore.removeLock( theLock ); 1840 ne_lock_destroy( theLock ); 1841 return true; 1842 } 1843 catch ( DAVException const & ) 1844 { 1845 } 1846 return false; 1847 */ 1848 } 1849 1850 // ------------------------------------------------------------------- 1851 // static 1852 bool 1853 CurlSession::getDataFromInputStream( 1854 const uno::Reference< io::XInputStream > & xStream, 1855 uno::Sequence< sal_Int8 > & rData, 1856 bool bAppendTrailingZeroByte ) 1857 { 1858 if ( xStream.is() ) 1859 { 1860 uno::Reference< io::XSeekable > xSeekable( xStream, uno::UNO_QUERY ); 1861 if ( xSeekable.is() ) 1862 { 1863 try 1864 { 1865 sal_Int32 nSize 1866 = sal::static_int_cast<sal_Int32>(xSeekable->getLength()); 1867 sal_Int32 nRead 1868 = xStream->readBytes( rData, nSize ); 1869 1870 if ( nRead == nSize ) 1871 { 1872 if ( bAppendTrailingZeroByte ) 1873 { 1874 rData.realloc( nSize + 1 ); 1875 rData[ nSize ] = sal_Int8( 0 ); 1876 } 1877 return true; 1878 } 1879 } 1880 catch ( io::NotConnectedException const & ) 1881 { 1882 // readBytes 1883 } 1884 catch ( io::BufferSizeExceededException const & ) 1885 { 1886 // readBytes 1887 } 1888 catch ( io::IOException const & ) 1889 { 1890 // getLength, readBytes 1891 } 1892 } 1893 else 1894 { 1895 try 1896 { 1897 uno::Sequence< sal_Int8 > aBuffer; 1898 sal_Int32 nPos = 0; 1899 1900 sal_Int32 nRead = xStream->readSomeBytes( aBuffer, 65536 ); 1901 while ( nRead > 0 ) 1902 { 1903 if ( rData.getLength() < ( nPos + nRead ) ) 1904 rData.realloc( nPos + nRead ); 1905 1906 aBuffer.realloc( nRead ); 1907 rtl_copyMemory( (void*)( rData.getArray() + nPos ), 1908 (const void*)aBuffer.getConstArray(), 1909 nRead ); 1910 nPos += nRead; 1911 1912 aBuffer.realloc( 0 ); 1913 nRead = xStream->readSomeBytes( aBuffer, 65536 ); 1914 } 1915 1916 if ( bAppendTrailingZeroByte ) 1917 { 1918 rData.realloc( nPos + 1 ); 1919 rData[ nPos ] = sal_Int8( 0 ); 1920 } 1921 return true; 1922 } 1923 catch ( io::NotConnectedException const & ) 1924 { 1925 // readBytes 1926 } 1927 catch ( io::BufferSizeExceededException const & ) 1928 { 1929 // readBytes 1930 } 1931 catch ( io::IOException const & ) 1932 { 1933 // readBytes 1934 } 1935 } 1936 } 1937 return false; 1938 } 1939 1940 // --------------------------------------------------------------------- 1941 sal_Bool 1942 CurlSession::isDomainMatch( rtl::OUString certHostName ) 1943 { 1944 rtl::OUString hostName = getHostName(); 1945 1946 if (hostName.equalsIgnoreAsciiCase( certHostName ) ) 1947 return sal_True; 1948 1949 if ( 0 == certHostName.indexOf( rtl::OUString::createFromAscii( "*" ) ) && 1950 hostName.getLength() >= certHostName.getLength() ) 1951 { 1952 rtl::OUString cmpStr = certHostName.copy( 1 ); 1953 1954 if ( hostName.matchIgnoreAsciiCase( 1955 cmpStr, hostName.getLength() - cmpStr.getLength() ) ) 1956 return sal_True; 1957 } 1958 return sal_False; 1959 } 1960