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 DAVException::ExceptionCode exCode = DAVException::DAV_HTTP_ERROR; 774 rtl::OUString exData; 775 switch (curlCode) { 776 case CURLE_COULDNT_RESOLVE_HOST: 777 exCode = DAVException::DAV_HTTP_LOOKUP; 778 exData = CurlUri::makeConnectionEndPointString( getHostName(), 779 getPort() ); 780 break; 781 case CURLE_COULDNT_CONNECT: 782 exCode = DAVException::DAV_HTTP_CONNECT; 783 exData = CurlUri::makeConnectionEndPointString( getHostName(), 784 getPort() ); 785 break; 786 case CURLE_OPERATION_TIMEDOUT: 787 exCode = DAVException::DAV_HTTP_TIMEOUT; 788 exData = CurlUri::makeConnectionEndPointString( getHostName(), 789 getPort() ); 790 break; 791 case CURLE_LOGIN_DENIED: 792 case CURLE_AUTH_ERROR: 793 exCode = DAVException::DAV_HTTP_AUTH; 794 exData = CurlUri::makeConnectionEndPointString( getHostName(), 795 getPort() ); 796 break; 797 default: 798 { 799 const char *s = curl_easy_strerror(curlCode); 800 exCode = DAVException::DAV_HTTP_ERROR; 801 exData = ::rtl::OUString(s, strlen(s), 802 RTL_TEXTENCODING_UTF8); 803 break; 804 } 805 } 806 throw DAVException( exCode, exData ); 807 } 808 809 rtl::OUString reasonPhrase = rtl::OStringToOUString( curlRequest.getReasonPhrase(), RTL_TEXTENCODING_UTF8 ); 810 if ( statusCode != 0 && statusCode / 100 != 2 ) 811 { 812 switch (statusCode) 813 { 814 case SC_MOVED_PERMANENTLY: // 301 815 case SC_MOVED_TEMPORARILY: // 302 816 case SC_SEE_OTHER: // 303 817 case SC_TEMPORARY_REDIRECT: // 307 818 { 819 // new location for certain redirections 820 821 const CurlRequest::Header *location = curlRequest.findResponseHeader( "location" ); 822 if ( location != NULL ) 823 { 824 m_aLogger.log( LogLevel::FINE, "HTTP $1$ response with new location = $2$", 825 statusCode, location->value ); 826 throw DAVException( DAVException::DAV_HTTP_REDIRECT, 827 rtl::OStringToOUString( location->value, RTL_TEXTENCODING_UTF8 ) ); 828 } 829 break; 830 } 831 case SC_UNAUTHORIZED: // 401 832 case SC_PROXY_AUTHENTICATION_REQUIRED: // 407 833 { 834 throw DAVException( DAVException::DAV_HTTP_ERROR, 835 reasonPhrase, 836 statusCode ); 837 break; 838 } 839 case SC_REQUEST_ENTITY_TOO_LARGE: // 413 840 { 841 if ( m_bTransferEncodingSwitched ) 842 throw DAVException( DAVException::DAV_HTTP_ERROR, 843 reasonPhrase, 844 statusCode ); 845 m_bTransferEncodingSwitched = true; 846 curlRequest.setChunkedEncoding( !curlRequest.isChunkedEncoding() ); 847 break; 848 } 849 case SC_LOCKED: // 423 850 throw DAVException( DAVException::DAV_LOCKED, 851 reasonPhrase, 852 statusCode ); 853 default: 854 throw DAVException( DAVException::DAV_HTTP_ERROR, 855 reasonPhrase, 856 statusCode ); 857 } 858 } 859 } 860 861 static void responseHeadersToDAVResource( const std::vector< CurlRequest::Header> &responseHeaders, 862 const std::vector< ::rtl::OUString > &inHeaderNames, 863 DAVResource &ioResource ) 864 { 865 std::vector< CurlRequest::Header >::const_iterator it( responseHeaders.begin() ); 866 const std::vector< CurlRequest::Header >::const_iterator end( responseHeaders.end() ); 867 while ( it != end ) 868 { 869 bool storeHeader = false; 870 if ( inHeaderNames.size() == 0 ) 871 storeHeader = true; 872 else 873 { 874 std::vector< ::rtl::OUString >::const_iterator reqIt( inHeaderNames.begin() ); 875 const std::vector< ::rtl::OUString >::const_iterator reqEnd( inHeaderNames.end() ); 876 while ( reqIt != reqEnd ) 877 { 878 // header names are case insensitive 879 if ( (*reqIt).equalsIgnoreAsciiCase( rtl::OStringToOUString( (*it).name, RTL_TEXTENCODING_UTF8 ) ) ) 880 { 881 storeHeader = true; 882 break; 883 } 884 else 885 { 886 ++reqIt; 887 } 888 } 889 } 890 891 if ( storeHeader ) 892 { 893 DAVPropertyValue thePropertyValue; 894 thePropertyValue.IsCaseSensitive = false; 895 thePropertyValue.Name = rtl::OStringToOUString( (*it).name, RTL_TEXTENCODING_UTF8 ); 896 thePropertyValue.Value <<= rtl::OStringToOUString( (*it).value, RTL_TEXTENCODING_UTF8 ); 897 ioResource.properties.push_back( thePropertyValue ); 898 } 899 900 it++; 901 } 902 } 903 904 // ------------------------------------------------------------------- 905 // PROPFIND - allprop & named 906 // ------------------------------------------------------------------- 907 908 void CurlSession::propfind( CurlRequest &curlRequest, 909 const rtl::OUString &inPath, 910 const Depth inDepth, 911 const std::vector< ::rtl::OUString > * inPropNames, 912 const bool onlyPropertyNames, 913 const DAVRequestEnvironment & rEnv ) 914 { 915 addEnvironmentRequestHeaders( curlRequest, rEnv ); 916 917 if ( inDepth == DAVZERO ) 918 curlRequest.addHeader( "Depth", "0" ); 919 else if ( inDepth == DAVONE ) 920 curlRequest.addHeader( "Depth", "1" ); 921 else if ( inDepth == DAVINFINITY ) 922 curlRequest.addHeader( "Depth", "infinity" ); 923 924 rtl::OString xml = PropfindRequest::generatePROPFINDRequestBody( inPropNames, onlyPropertyNames ); 925 if ( xml.getLength() > 0 ) 926 { 927 curlRequest.addHeader( "Content-Type", "application/xml" ); 928 curlRequest.setRequestBody( xml.getStr(), xml.getLength() ); 929 } 930 931 CredentialsData credsData( this, curlRequest, rEnv ); 932 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 933 934 CURLcode rc = curlRequest.propfind( m_aUri, inPath ); 935 processResponse( curlRequest, rc ); 936 } 937 938 void CurlSession::PROPFIND( const rtl::OUString & inPath, 939 const Depth inDepth, 940 const std::vector< rtl::OUString > & inPropNames, 941 std::vector< DAVResource > & ioResources, 942 const DAVRequestEnvironment & rEnv ) 943 throw ( DAVException ) 944 { 945 m_aLogger.log( LogLevel::INFO, "PROPFIND line $1$", (sal_Int32)__LINE__ ); 946 947 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 948 949 Init( rEnv ); 950 CurlRequest curlRequest( m_pCurl ); 951 952 propfind( curlRequest, inPath, inDepth, &inPropNames, false, rEnv ); 953 954 const std::vector< DAVResource > rResources( parseWebDAVPropFindResponse( curlRequest.getResponseBody().get() ) ); 955 std::vector< DAVResource > *pIoResources = &ioResources; 956 *pIoResources = rResources; 957 } 958 959 // ------------------------------------------------------------------- 960 // PROPFIND - propnames 961 // ------------------------------------------------------------------- 962 void CurlSession::PROPFIND( const rtl::OUString & inPath, 963 const Depth inDepth, 964 std::vector< DAVResourceInfo > & ioResInfo, 965 const DAVRequestEnvironment & rEnv ) 966 throw( DAVException ) 967 { 968 m_aLogger.log( LogLevel::INFO, "PROPFIND line $1$", (sal_Int32)__LINE__ ); 969 970 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 971 972 Init( rEnv ); 973 CurlRequest curlRequest( m_pCurl ); 974 975 propfind( curlRequest, inPath, inDepth, NULL, true, rEnv ); 976 977 const std::vector< DAVResourceInfo > rResInfo( parseWebDAVPropNameResponse( curlRequest.getResponseBody().get() ) ); 978 std::vector< DAVResourceInfo > *pIoResInfo = &ioResInfo; 979 *pIoResInfo = rResInfo; 980 } 981 982 // ------------------------------------------------------------------- 983 // PROPPATCH 984 // ------------------------------------------------------------------- 985 void CurlSession::PROPPATCH( const rtl::OUString & inPath, 986 const std::vector< ProppatchValue > & inValues, 987 const DAVRequestEnvironment & rEnv ) 988 throw( DAVException ) 989 { 990 m_aLogger.log( LogLevel::INFO, "PROPPATCH line $1$", (sal_Int32)__LINE__ ); 991 992 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 993 994 Init( rEnv ); 995 CurlRequest curlRequest( m_pCurl ); 996 997 addEnvironmentRequestHeaders( curlRequest, rEnv ); 998 999 // check whether a lock on this resource is already owned 1000 rtl::OUString aUri( composeCurrentUri( inPath ) ); 1001 ucb::Lock inLock; 1002 CurlLock * pLock = m_aCurlLockStore.findByUri( aUri ); 1003 if ( pLock ) 1004 { 1005 inLock = pLock->getLock(); 1006 } 1007 if ( inLock.LockTokens.getLength() > 0 ) 1008 { 1009 curlRequest.addHeader( "If", 1010 ( "(<" + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ) + ">)" ).getStr() ); 1011 } 1012 1013 rtl::OString xml = ProppatchRequest::generatePROPPATCHRequestBody( inValues ); 1014 if ( xml.getLength() > 0 ) 1015 { 1016 curlRequest.addHeader( "Content-Type", "application/xml" ); 1017 curlRequest.setRequestBody( xml.getStr(), xml.getLength() ); 1018 } 1019 1020 CredentialsData credsData( this, curlRequest, rEnv ); 1021 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1022 1023 CURLcode rc = curlRequest.proppatch( m_aUri, inPath ); 1024 processResponse( curlRequest, rc ); 1025 } 1026 1027 // ------------------------------------------------------------------- 1028 // HEAD 1029 // ------------------------------------------------------------------- 1030 void CurlSession::HEAD( const ::rtl::OUString & inPath, 1031 const std::vector< ::rtl::OUString > & inHeaderNames, 1032 DAVResource & ioResource, 1033 const DAVRequestEnvironment & rEnv ) 1034 throw( DAVException ) 1035 { 1036 m_aLogger.log( LogLevel::INFO, "HEAD line $1$", (sal_Int32)__LINE__ ); 1037 1038 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1039 1040 Init(rEnv ); 1041 CurlRequest curlRequest( m_pCurl ); 1042 1043 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1044 1045 ioResource.uri = inPath; 1046 ioResource.properties.clear(); 1047 1048 CredentialsData credsData( this, curlRequest, rEnv ); 1049 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1050 1051 CURLcode rc = curlRequest.head( m_aUri, inPath ); 1052 processResponse( curlRequest, rc ); 1053 responseHeadersToDAVResource( curlRequest.getResponseHeaders(), inHeaderNames, ioResource ); 1054 } 1055 1056 // ------------------------------------------------------------------- 1057 // GET 1058 // ------------------------------------------------------------------- 1059 uno::Reference< io::XInputStream > 1060 CurlSession::GET( const rtl::OUString & inPath, 1061 const DAVRequestEnvironment & rEnv ) 1062 throw ( DAVException ) 1063 { 1064 m_aLogger.log( LogLevel::INFO, "GET line $1$", (sal_Int32)__LINE__ ); 1065 1066 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1067 1068 Init( rEnv ); 1069 CurlRequest curlRequest( m_pCurl ); 1070 1071 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1072 1073 CredentialsData credsData( this, curlRequest, rEnv ); 1074 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1075 1076 CURLcode rc = curlRequest.get( m_aUri, inPath ); 1077 processResponse( curlRequest, rc ); 1078 1079 return uno::Reference< io::XInputStream >( curlRequest.getResponseBody().get() ); 1080 } 1081 1082 // ------------------------------------------------------------------- 1083 // GET 1084 // ------------------------------------------------------------------- 1085 void CurlSession::GET( const rtl::OUString & inPath, 1086 uno::Reference< io::XOutputStream > & ioOutputStream, 1087 const DAVRequestEnvironment & rEnv ) 1088 throw ( DAVException ) 1089 { 1090 m_aLogger.log( LogLevel::INFO, "GET line $1$", (sal_Int32)__LINE__ ); 1091 1092 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1093 1094 Init( rEnv ); 1095 CurlRequest curlRequest( m_pCurl ); 1096 1097 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1098 1099 CredentialsData credsData( this, curlRequest, rEnv ); 1100 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1101 1102 curlRequest.saveResponseBodyTo( ioOutputStream ); 1103 CURLcode rc = curlRequest.get( m_aUri, inPath ); 1104 processResponse( curlRequest, rc ); 1105 } 1106 1107 // ------------------------------------------------------------------- 1108 // GET 1109 // ------------------------------------------------------------------- 1110 uno::Reference< io::XInputStream > 1111 CurlSession::GET( const rtl::OUString & inPath, 1112 const std::vector< ::rtl::OUString > & inHeaderNames, 1113 DAVResource & ioResource, 1114 const DAVRequestEnvironment & rEnv ) 1115 throw ( DAVException ) 1116 { 1117 m_aLogger.log( LogLevel::INFO, "GET line $1$", (sal_Int32)__LINE__ ); 1118 1119 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1120 1121 Init( rEnv ); 1122 CurlRequest curlRequest( m_pCurl ); 1123 1124 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1125 1126 CredentialsData credsData( this, curlRequest, rEnv ); 1127 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1128 1129 CURLcode rc = curlRequest.get( m_aUri, inPath ); 1130 processResponse( curlRequest, rc ); 1131 responseHeadersToDAVResource( curlRequest.getResponseHeaders(), inHeaderNames, ioResource ); 1132 1133 return uno::Reference< io::XInputStream >( curlRequest.getResponseBody().get() ); 1134 } 1135 1136 1137 // ------------------------------------------------------------------- 1138 // GET 1139 // ------------------------------------------------------------------- 1140 void CurlSession::GET( const rtl::OUString & inPath, 1141 uno::Reference< io::XOutputStream > & ioOutputStream, 1142 const std::vector< ::rtl::OUString > & inHeaderNames, 1143 DAVResource & ioResource, 1144 const DAVRequestEnvironment & rEnv ) 1145 throw ( DAVException ) 1146 { 1147 m_aLogger.log( LogLevel::INFO, "GET line $1$", (sal_Int32)__LINE__ ); 1148 1149 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1150 1151 Init( rEnv ); 1152 CurlRequest curlRequest( m_pCurl ); 1153 1154 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1155 1156 CredentialsData credsData( this, curlRequest, rEnv ); 1157 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1158 1159 curlRequest.saveResponseBodyTo( ioOutputStream ); 1160 CURLcode rc = curlRequest.get( m_aUri, inPath ); 1161 processResponse( curlRequest, rc ); 1162 responseHeadersToDAVResource( curlRequest.getResponseHeaders(), inHeaderNames, ioResource ); 1163 } 1164 1165 // ------------------------------------------------------------------- 1166 // PUT 1167 // ------------------------------------------------------------------- 1168 void CurlSession::PUT( const rtl::OUString & inPath, 1169 const uno::Reference< io::XInputStream > & inInputStream, 1170 const DAVRequestEnvironment & rEnv ) 1171 throw ( DAVException ) 1172 { 1173 m_aLogger.log( LogLevel::INFO, "PUT line $1$", (sal_Int32)__LINE__ ); 1174 1175 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1176 1177 Init( rEnv ); 1178 CurlRequest curlRequest( m_pCurl ); 1179 1180 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1181 1182 uno::Sequence< sal_Int8 > aDataToSend; 1183 if ( !getDataFromInputStream( inInputStream, aDataToSend, false ) ) 1184 throw DAVException( DAVException::DAV_INVALID_ARG ); 1185 curlRequest.setRequestBody( reinterpret_cast< const char * >( aDataToSend.getConstArray() ), 1186 aDataToSend.getLength() ); 1187 1188 CredentialsData credsData( this, curlRequest, rEnv ); 1189 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1190 1191 // check whether a lock on this resource is already owned 1192 rtl::OUString aUri( composeCurrentUri( inPath ) ); 1193 ucb::Lock inLock; 1194 CurlLock * pLock = m_aCurlLockStore.findByUri( aUri ); 1195 if ( pLock ) 1196 { 1197 inLock = pLock->getLock(); 1198 } 1199 if ( inLock.LockTokens.getLength() > 0 ) 1200 { 1201 curlRequest.addHeader( "If", 1202 ( "(<" + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ) + ">)" ).getStr() ); 1203 } 1204 1205 CURLcode rc = curlRequest.put( m_aUri, inPath ); 1206 processResponse( curlRequest, rc ); 1207 } 1208 1209 // ------------------------------------------------------------------- 1210 // POST 1211 // ------------------------------------------------------------------- 1212 uno::Reference< io::XInputStream > 1213 CurlSession::POST( const rtl::OUString & inPath, 1214 const rtl::OUString & rContentType, 1215 const rtl::OUString & rReferer, 1216 const uno::Reference< io::XInputStream > & inInputStream, 1217 const DAVRequestEnvironment & rEnv ) 1218 throw ( DAVException ) 1219 { 1220 m_aLogger.log( LogLevel::INFO, "POST line $1$", (sal_Int32)__LINE__ ); 1221 1222 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1223 1224 Init( rEnv ); 1225 CurlRequest curlRequest( m_pCurl ); 1226 1227 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1228 1229 uno::Sequence< sal_Int8 > aDataToSend; 1230 if ( !getDataFromInputStream( inInputStream, aDataToSend, false ) ) 1231 throw DAVException( DAVException::DAV_INVALID_ARG ); 1232 curlRequest.setRequestBody( reinterpret_cast< const char * >( aDataToSend.getConstArray() ), 1233 aDataToSend.getLength() ); 1234 1235 CredentialsData credsData( this, curlRequest, rEnv ); 1236 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1237 1238 if ( !rContentType.isEmpty() ) 1239 curlRequest.addHeader( "Content-Type", rtl::OUStringToOString( rContentType, RTL_TEXTENCODING_UTF8 ).getStr() ); 1240 if ( !rReferer.isEmpty() ) 1241 curlRequest.addHeader( "Referer", rtl::OUStringToOString( rReferer, RTL_TEXTENCODING_UTF8 ).getStr() ); 1242 1243 // check whether a lock on this resource is already owned 1244 rtl::OUString aUri( composeCurrentUri( inPath ) ); 1245 ucb::Lock inLock; 1246 CurlLock * pLock = m_aCurlLockStore.findByUri( aUri ); 1247 if ( pLock ) 1248 { 1249 inLock = pLock->getLock(); 1250 } 1251 if ( inLock.LockTokens.getLength() > 0 ) 1252 { 1253 curlRequest.addHeader( "If", 1254 ( "(<" + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ) + ">)" ).getStr() ); 1255 } 1256 1257 CURLcode rc = curlRequest.post( m_aUri, inPath ); 1258 processResponse( curlRequest, rc ); 1259 return uno::Reference< io::XInputStream >( curlRequest.getResponseBody().get() ); 1260 } 1261 1262 // ------------------------------------------------------------------- 1263 // POST 1264 // ------------------------------------------------------------------- 1265 void CurlSession::POST( const rtl::OUString & inPath, 1266 const rtl::OUString & rContentType, 1267 const rtl::OUString & rReferer, 1268 const uno::Reference< io::XInputStream > & inInputStream, 1269 uno::Reference< io::XOutputStream > & oOutputStream, 1270 const DAVRequestEnvironment & rEnv ) 1271 throw ( DAVException ) 1272 { 1273 m_aLogger.log( LogLevel::INFO, "POST line $1$", (sal_Int32)__LINE__ ); 1274 1275 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1276 1277 Init( rEnv ); 1278 CurlRequest curlRequest( m_pCurl ); 1279 1280 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1281 1282 uno::Sequence< sal_Int8 > aDataToSend; 1283 if ( !getDataFromInputStream( inInputStream, aDataToSend, false ) ) 1284 throw DAVException( DAVException::DAV_INVALID_ARG ); 1285 curlRequest.setRequestBody( reinterpret_cast< const char * >( aDataToSend.getConstArray() ), 1286 aDataToSend.getLength() ); 1287 1288 CredentialsData credsData( this, curlRequest, rEnv ); 1289 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1290 1291 if ( !rContentType.isEmpty() ) 1292 curlRequest.addHeader( "Content-Type", rtl::OUStringToOString( rContentType, RTL_TEXTENCODING_UTF8 ).getStr() ); 1293 if ( !rReferer.isEmpty() ) 1294 curlRequest.addHeader( "Referer", rtl::OUStringToOString( rReferer, RTL_TEXTENCODING_UTF8 ).getStr() ); 1295 1296 // check whether a lock on this resource is already owned 1297 rtl::OUString aUri( composeCurrentUri( inPath ) ); 1298 ucb::Lock inLock; 1299 CurlLock * pLock = m_aCurlLockStore.findByUri( aUri ); 1300 if ( pLock ) 1301 { 1302 inLock = pLock->getLock(); 1303 } 1304 if ( inLock.LockTokens.getLength() > 0 ) 1305 { 1306 curlRequest.addHeader( "If", 1307 ( "(<" + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ) + ">)" ).getStr() ); 1308 } 1309 1310 curlRequest.saveResponseBodyTo( oOutputStream ); 1311 CURLcode rc = curlRequest.post( m_aUri, inPath ); 1312 processResponse( curlRequest, rc ); 1313 } 1314 1315 // ------------------------------------------------------------------- 1316 // MKCOL 1317 // ------------------------------------------------------------------- 1318 void CurlSession::MKCOL( const rtl::OUString & inPath, 1319 const DAVRequestEnvironment & rEnv ) 1320 throw ( DAVException ) 1321 { 1322 m_aLogger.log( LogLevel::INFO, "MKCOL line $1$", (sal_Int32)__LINE__ ); 1323 1324 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1325 1326 Init( rEnv ); 1327 CurlRequest curlRequest( m_pCurl ); 1328 1329 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1330 1331 CredentialsData credsData( this, curlRequest, rEnv ); 1332 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1333 1334 // check whether a lock on this resource is already owned 1335 rtl::OUString aUri( composeCurrentUri( inPath ) ); 1336 ucb::Lock inLock; 1337 CurlLock * pLock = m_aCurlLockStore.findByUri( aUri ); 1338 if ( pLock ) 1339 { 1340 inLock = pLock->getLock(); 1341 } 1342 if ( inLock.LockTokens.getLength() > 0 ) 1343 { 1344 curlRequest.addHeader( "If", 1345 ( "(<" + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ) + ">)" ).getStr() ); 1346 } 1347 1348 CURLcode rc = curlRequest.mkcol( m_aUri, inPath ); 1349 processResponse( curlRequest, rc ); 1350 } 1351 1352 // ------------------------------------------------------------------- 1353 // COPY 1354 // ------------------------------------------------------------------- 1355 void CurlSession::COPY( const rtl::OUString & inSourceURL, 1356 const rtl::OUString & inDestinationURL, 1357 const DAVRequestEnvironment & rEnv, 1358 sal_Bool inOverWrite ) 1359 throw ( DAVException ) 1360 { 1361 m_aLogger.log( LogLevel::INFO, "COPY line $1$", (sal_Int32)__LINE__ ); 1362 1363 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1364 1365 Init( rEnv ); 1366 CurlRequest curlRequest( m_pCurl ); 1367 1368 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1369 1370 CredentialsData credsData( this, curlRequest, rEnv ); 1371 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1372 1373 curlRequest.addHeader( "Destination", rtl::OUStringToOString( inDestinationURL, RTL_TEXTENCODING_UTF8 ).getStr() ); 1374 curlRequest.addHeader( "Overwrite", inOverWrite? "T" : "F" ); 1375 1376 // check whether a lock on the destination resource is already owned 1377 rtl::OUString aUri( composeCurrentUri( inDestinationURL ) ); 1378 ucb::Lock inLock; 1379 CurlLock * pLock = m_aCurlLockStore.findByUri( aUri ); 1380 if ( pLock ) 1381 { 1382 inLock = pLock->getLock(); 1383 } 1384 if ( inLock.LockTokens.getLength() > 0 ) 1385 { 1386 curlRequest.addHeader( "If", 1387 ( "(<" + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ) + ">)" ).getStr() ); 1388 } 1389 1390 CURLcode rc = curlRequest.copy( m_aUri, CurlUri( inSourceURL ).GetPath() ); 1391 processResponse( curlRequest, rc ); 1392 } 1393 1394 // ------------------------------------------------------------------- 1395 // MOVE 1396 // ------------------------------------------------------------------- 1397 void CurlSession::MOVE( const rtl::OUString & inSourceURL, 1398 const rtl::OUString & inDestinationURL, 1399 const DAVRequestEnvironment & rEnv, 1400 sal_Bool inOverWrite ) 1401 throw ( DAVException ) 1402 { 1403 m_aLogger.log( LogLevel::INFO, "MOVE line $1$", (sal_Int32)__LINE__ ); 1404 1405 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1406 1407 Init( rEnv ); 1408 CurlRequest curlRequest( m_pCurl ); 1409 1410 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1411 1412 CredentialsData credsData( this, curlRequest, rEnv ); 1413 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1414 1415 curlRequest.addHeader( "Destination", rtl::OUStringToOString( inDestinationURL, RTL_TEXTENCODING_UTF8 ).getStr() ); 1416 curlRequest.addHeader( "Overwrite", inOverWrite? "T" : "F" ); 1417 1418 // check whether a lock on the destination resource is already owned 1419 rtl::OUString aUri( composeCurrentUri( inDestinationURL ) ); 1420 ucb::Lock inLock; 1421 CurlLock * pLock = m_aCurlLockStore.findByUri( aUri ); 1422 if ( pLock ) 1423 { 1424 inLock = pLock->getLock(); 1425 } 1426 if ( inLock.LockTokens.getLength() > 0 ) 1427 { 1428 curlRequest.addHeader( "If", 1429 ( "(<" + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ) + ">)" ).getStr() ); 1430 } 1431 1432 CURLcode rc = curlRequest.copy( m_aUri, CurlUri( inSourceURL ).GetPath() ); 1433 processResponse( curlRequest, rc ); 1434 } 1435 1436 // ------------------------------------------------------------------- 1437 // DESTROY 1438 // ------------------------------------------------------------------- 1439 void CurlSession::DESTROY( const rtl::OUString & inPath, 1440 const DAVRequestEnvironment & rEnv ) 1441 throw ( DAVException ) 1442 { 1443 m_aLogger.log( LogLevel::INFO, "DESTROY line $1$", (sal_Int32)__LINE__ ); 1444 1445 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1446 1447 Init( rEnv ); 1448 CurlRequest curlRequest( m_pCurl ); 1449 1450 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1451 1452 CredentialsData credsData( this, curlRequest, rEnv ); 1453 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1454 1455 // check whether a lock on this resource is already owned 1456 rtl::OUString aUri( composeCurrentUri( inPath ) ); 1457 ucb::Lock inLock; 1458 CurlLock * pLock = m_aCurlLockStore.findByUri( aUri ); 1459 if ( pLock ) 1460 { 1461 inLock = pLock->getLock(); 1462 } 1463 if ( inLock.LockTokens.getLength() > 0 ) 1464 { 1465 curlRequest.addHeader( "If", 1466 ( "(<" + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ) + ">)" ).getStr() ); 1467 } 1468 1469 CURLcode rc = curlRequest.delete_( m_aUri, inPath ); 1470 processResponse( curlRequest, rc ); 1471 } 1472 1473 // ------------------------------------------------------------------- 1474 1475 namespace 1476 { 1477 sal_Int32 lastChanceToSendRefreshRequest( TimeValue const & rStart, 1478 sal_Int32 timeout ) 1479 { 1480 TimeValue aEnd; 1481 osl_getSystemTime( &aEnd ); 1482 1483 // Try to estimate a safe absolute time for sending the 1484 // lock refresh request. 1485 sal_Int32 lastChanceToSendRefreshRequest = DAVINFINITY; 1486 if ( timeout != DAVINFINITY ) 1487 { 1488 sal_Int32 calltime = aEnd.Seconds - rStart.Seconds; 1489 if ( calltime <= timeout ) 1490 { 1491 lastChanceToSendRefreshRequest 1492 = aEnd.Seconds + timeout - calltime; 1493 } 1494 else 1495 { 1496 OSL_TRACE( "No chance to refresh lock before timeout!" ); 1497 } 1498 } 1499 return lastChanceToSendRefreshRequest; 1500 } 1501 1502 } // namespace 1503 1504 // ------------------------------------------------------------------- 1505 // LOCK (set new lock) 1506 // ------------------------------------------------------------------- 1507 void CurlSession::LOCK( const ::rtl::OUString & inPath, 1508 ucb::Lock & inLock, 1509 const DAVRequestEnvironment & rEnv ) 1510 throw ( DAVException ) 1511 { 1512 m_aLogger.log( LogLevel::INFO, "LOCK line $1$", (sal_Int32)__LINE__ ); 1513 1514 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1515 1516 // before locking, search in the lock store if we already own a lock for this resource 1517 // if present, return with exception DAV_LOCKED_SELF 1518 rtl::OUString aUri( composeCurrentUri( inPath ) ); 1519 CurlLock * pLock = m_aCurlLockStore.findByUri( aUri ); 1520 if ( pLock ) 1521 { 1522 // already present, meaning already locked by the same AOO session and already in the lockstore 1523 // just return, nothing to do 1524 return; 1525 } 1526 1527 Init( rEnv ); 1528 CurlRequest curlRequest( m_pCurl ); 1529 1530 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1531 1532 CredentialsData credsData( this, curlRequest, rEnv ); 1533 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1534 1535 if ( inLock.Timeout == -1 ) 1536 curlRequest.addHeader( "Timeout", "Infinite" ); 1537 else 1538 curlRequest.addHeader( "Timeout", "Second-" + rtl::OString::valueOf( inLock.Timeout ) ); 1539 1540 switch ( inLock.Depth ) 1541 { 1542 //i126305 TODO investigate on this case... 1543 case ucb::LockDepth_MAKE_FIXED_SIZE: 1544 1545 case ucb::LockDepth_ZERO: 1546 curlRequest.addHeader( "Depth", "0" ); 1547 break; 1548 case ucb::LockDepth_ONE: 1549 curlRequest.addHeader( "Depth", "1" ); 1550 break; 1551 case ucb::LockDepth_INFINITY: 1552 curlRequest.addHeader( "Depth", "infinity" ); 1553 break; 1554 } 1555 1556 rtl::OString xml = LockRequest::generateRequestBody( inLock ); 1557 curlRequest.addHeader( "Content-Type", "application/xml" ); 1558 curlRequest.setRequestBody( xml.getStr(), xml.getLength() ); 1559 1560 TimeValue startCall; 1561 osl_getSystemTime( &startCall ); 1562 1563 CURLcode rc = curlRequest.lock( m_aUri, inPath ); 1564 processResponse( curlRequest, rc ); 1565 1566 // the returned property, a sequence of locks 1567 // only the first is used 1568 const DAVPropertyValue outLock( parseWebDAVLockResponse( curlRequest.getResponseBody().get() ) ); 1569 if(outLock.Name.compareToAscii(RTL_CONSTASCII_STRINGPARAM( "DAV:lockdiscovery" )) == 0 ) 1570 { 1571 // got a lock, use only the first returned 1572 uno::Sequence< ucb::Lock > aLocks; 1573 outLock.Value >>= aLocks; 1574 ucb::Lock aLock = aLocks[0]; 1575 1576 CurlLock* aNewLock = new CurlLock( aLock, aUri, inPath ); 1577 // add the store the new lock 1578 m_aCurlLockStore.addLock(aNewLock,this, 1579 lastChanceToSendRefreshRequest( 1580 startCall, static_cast< sal_Int32 >(aLock.Timeout) ) ); 1581 } 1582 } 1583 1584 // ------------------------------------------------------------------- 1585 // LOCK (refresh existing lock from DAVResourceAccess) 1586 // ------------------------------------------------------------------- 1587 sal_Int64 CurlSession::LOCK( const ::rtl::OUString & /*inPath*/, 1588 sal_Int64 nTimeout, 1589 const DAVRequestEnvironment & /*rEnv*/ ) 1590 throw ( DAVException ) 1591 { 1592 m_aLogger.log( LogLevel::INFO, "LOCK line $1$", (sal_Int32)__LINE__ ); 1593 1594 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1595 1596 return nTimeout; 1597 /* 1598 // Try to get the neon lock from lock store 1599 CurlLock * theLock 1600 = m_aCurlLockStore.findByUri( makeAbsoluteURL( inPath ) ); 1601 if ( !theLock ) 1602 throw DAVException( DAVException::DAV_NOT_LOCKED ); 1603 1604 Init( rEnv ); 1605 1606 // refresh existing lock. 1607 theLock->timeout = static_cast< long >( nTimeout ); 1608 1609 TimeValue startCall; 1610 osl_getSystemTime( &startCall ); 1611 1612 int theRetVal = ne_lock_refresh( m_pHttpSession, theLock ); 1613 1614 if ( theRetVal == NE_OK ) 1615 { 1616 m_aCurlLockStore.updateLock( theLock, 1617 lastChanceToSendRefreshRequest( 1618 startCall, theLock->timeout ) ); 1619 } 1620 1621 HandleError( theRetVal, inPath, rEnv ); 1622 1623 return theLock->timeout; 1624 */ 1625 } 1626 1627 // ------------------------------------------------------------------- 1628 // LOCK (refresh existing lock from CurlLockStore) 1629 // ------------------------------------------------------------------- 1630 bool CurlSession::LOCK( CurlLock * pLock, 1631 sal_Int32 & rlastChanceToSendRefreshRequest ) 1632 { 1633 m_aLogger.log( LogLevel::INFO, "LOCK line $1$", (sal_Int32)__LINE__ ); 1634 1635 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1636 1637 Init(); 1638 CurlRequest curlRequest( m_pCurl ); 1639 1640 const ucb::Lock & inLock = pLock->getLock(); 1641 rtl::OUString inPath = pLock->getResourcePath(); 1642 1643 if ( inLock.Timeout == -1 ) 1644 curlRequest.addHeader( "Timeout", "Infinite" ); 1645 else 1646 curlRequest.addHeader( "Timeout", "Second-" + rtl::OString::valueOf( inLock.Timeout ) ); 1647 1648 switch ( inLock.Depth ) 1649 { 1650 //i126305 TODO investigate on this case... 1651 case ucb::LockDepth_MAKE_FIXED_SIZE: 1652 1653 case ucb::LockDepth_ZERO: 1654 curlRequest.addHeader( "Depth", "0" ); 1655 break; 1656 case ucb::LockDepth_ONE: 1657 curlRequest.addHeader( "Depth", "1" ); 1658 break; 1659 case ucb::LockDepth_INFINITY: 1660 curlRequest.addHeader( "Depth", "infinity" ); 1661 break; 1662 } 1663 1664 if ( inLock.LockTokens.getLength() > 0 ) 1665 { 1666 curlRequest.addHeader( "If", 1667 ( "(<" + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ) + ">)" ).getStr() ); 1668 } 1669 1670 rtl::OString xml = LockRequest::generateRequestBody( inLock ); 1671 curlRequest.addHeader( "Content-Type", "application/xml" ); 1672 curlRequest.setRequestBody( xml.getStr(), xml.getLength() ); 1673 1674 TimeValue startCall; 1675 osl_getSystemTime( &startCall ); 1676 1677 CURLcode rc = curlRequest.lock( m_aUri, inPath ); 1678 processResponse( curlRequest, rc ); 1679 1680 // the returned property, a sequence of locks 1681 // only the first is used 1682 const DAVPropertyValue outLock( parseWebDAVLockResponse( curlRequest.getResponseBody().get() ) ); 1683 uno::Sequence< ucb::Lock > aLocks; 1684 outLock.Value >>= aLocks; 1685 ucb::Lock aLock = aLocks[0]; 1686 1687 // if ok, update the lastchance refresh time in lock 1688 rlastChanceToSendRefreshRequest 1689 = lastChanceToSendRefreshRequest( startCall, static_cast< sal_Int32 >(aLock.Timeout) ); 1690 1691 return true; 1692 } 1693 1694 // ------------------------------------------------------------------- 1695 // UNLOCK called from external (DAVResourceAccess) 1696 // ------------------------------------------------------------------- 1697 void CurlSession::UNLOCK( const ::rtl::OUString & inPath, 1698 const DAVRequestEnvironment & rEnv ) 1699 throw ( DAVException ) 1700 { 1701 m_aLogger.log( LogLevel::INFO, "UNLOCK line $1$", (sal_Int32)__LINE__ ); 1702 1703 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1704 1705 rtl::OUString aUri( composeCurrentUri( inPath ) ); 1706 CurlLock * pLock = m_aCurlLockStore.findByUri( aUri ); 1707 if ( !pLock ) 1708 { 1709 throw DAVException( DAVException::DAV_NOT_LOCKED ); 1710 } 1711 1712 Init( rEnv ); 1713 CurlRequest curlRequest( m_pCurl ); 1714 1715 addEnvironmentRequestHeaders( curlRequest, rEnv ); 1716 1717 CredentialsData credsData( this, curlRequest, rEnv ); 1718 curlRequest.setProvideCredentialsCallback( Curl_ProvideCredentials, &credsData ); 1719 1720 ucb::Lock inLock = pLock->getLock(); 1721 curlRequest.addHeader( "Lock-Token", 1722 ( "<" + rtl::OUStringToOString( inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ) + ">" ).getStr() ); 1723 1724 // remove lock from lockstore 1725 // so, if something goes wrong, we don't refresh it anymore 1726 m_aCurlLockStore.removeLock( pLock ); 1727 delete pLock; 1728 1729 CURLcode rc = curlRequest.unlock( m_aUri, inPath ); 1730 processResponse( curlRequest, rc ); 1731 } 1732 1733 // ------------------------------------------------------------------- 1734 // UNLOCK (called from CurlLockStore) 1735 // ------------------------------------------------------------------- 1736 bool CurlSession::UNLOCK( CurlLock * pLock ) 1737 { 1738 m_aLogger.log( LogLevel::INFO, "UNLOCK line $1$", (sal_Int32)__LINE__ ); 1739 1740 osl::Guard< osl::Mutex > theGuard( m_aMutex ); 1741 1742 Init(); 1743 CurlRequest curlRequest( m_pCurl ); 1744 1745 rtl::OUString inPath = pLock->getResourcePath(); 1746 ucb::Lock inLock = pLock->getLock(); 1747 curlRequest.addHeader( "Lock-Token", 1748 ( "<" + rtl::OUStringToOString( inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ) + ">" ).getStr() ); 1749 1750 CURLcode rc = curlRequest.unlock( m_aUri, inPath ); 1751 processResponse( curlRequest, rc ); 1752 return true; 1753 } 1754 1755 // ------------------------------------------------------------------- 1756 void CurlSession::abort() 1757 throw ( DAVException ) 1758 { 1759 // 11.11.09 (tkr): The following code lines causing crashes if 1760 // closing a ongoing connection. It turned out that this existing 1761 // solution doesn't work in multi-threading environments. 1762 // So I disabled them in 3.2. . Issue #73893# should fix it in OOo 3.3. 1763 //if ( m_pHttpSession ) 1764 // ne_close_connection( m_pHttpSession ); 1765 } 1766 1767 // ------------------------------------------------------------------- 1768 const ucbhelper::InternetProxyServer & CurlSession::getProxySettings() const 1769 { 1770 if ( m_aUri.GetScheme().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "http" ) ) || 1771 m_aUri.GetScheme().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "https" ) ) ) 1772 { 1773 return m_rProxyDecider.getProxy( m_aUri.GetScheme(), 1774 m_aUri.GetHost(), 1775 m_aUri.GetPort() ); 1776 } 1777 else 1778 { 1779 // TODO: figure out, if this case can occur 1780 return m_rProxyDecider.getProxy( m_aUri.GetScheme(), 1781 rtl::OUString() /* not used */, 1782 -1 /* not used */ ); 1783 } 1784 } 1785 1786 /* 1787 // ------------------------------------------------------------------- 1788 namespace { 1789 1790 bool containsLocktoken( const uno::Sequence< ucb::Lock > & rLocks, 1791 const char * token ) 1792 { 1793 for ( sal_Int32 n = 0; n < rLocks.getLength(); ++n ) 1794 { 1795 const uno::Sequence< rtl::OUString > & rTokens 1796 = rLocks[ n ].LockTokens; 1797 for ( sal_Int32 m = 0; m < rTokens.getLength(); ++m ) 1798 { 1799 if ( rTokens[ m ].equalsAscii( token ) ) 1800 return true; 1801 } 1802 } 1803 return false; 1804 } 1805 1806 } // namespace 1807 */ 1808 1809 // ------------------------------------------------------------------- 1810 // This method doesn't seem to be used. 1811 // In any case the default behavior is to ask a lock with a life of 3 minutes 1812 // it will then be refreshed automatically (see CurlLockStore class) 1813 // In case of AOO crash the lock will expire by itself 1814 bool CurlSession::removeExpiredLocktoken( const rtl::OUString & /*inURL*/, 1815 const DAVRequestEnvironment & /*rEnv*/ ) 1816 { 1817 return true; 1818 /* 1819 CurlLock * theLock = m_aCurlLockStore.findByUri( inURL ); 1820 if ( !theLock ) 1821 return false; 1822 1823 // do a lockdiscovery to check whether this lock is still valid. 1824 try 1825 { 1826 // @@@ Alternative: use ne_lock_discover() => less overhead 1827 1828 std::vector< DAVResource > aResources; 1829 std::vector< rtl::OUString > aPropNames; 1830 aPropNames.push_back( DAVProperties::LOCKDISCOVERY ); 1831 1832 PROPFIND( rEnv.m_aRequestURI, DAVZERO, aPropNames, aResources, rEnv ); 1833 1834 if ( aResources.size() == 0 ) 1835 return false; 1836 1837 std::vector< DAVPropertyValue >::const_iterator it 1838 = aResources[ 0 ].properties.begin(); 1839 std::vector< DAVPropertyValue >::const_iterator end 1840 = aResources[ 0 ].properties.end(); 1841 1842 while ( it != end ) 1843 { 1844 if ( (*it).Name.equals( DAVProperties::LOCKDISCOVERY ) ) 1845 { 1846 uno::Sequence< ucb::Lock > aLocks; 1847 if ( !( (*it).Value >>= aLocks ) ) 1848 return false; 1849 1850 if ( !containsLocktoken( aLocks, theLock->token ) ) 1851 { 1852 // expired! 1853 break; 1854 } 1855 1856 // still valid. 1857 return false; 1858 } 1859 ++it; 1860 } 1861 1862 // No lockdiscovery prop in propfind result / locktoken not found 1863 // in propfind result -> not locked 1864 OSL_TRACE( "CurlSession::removeExpiredLocktoken: Removing " 1865 " expired lock token for %s. token: %s", 1866 rtl::OUStringToOString( inURL, 1867 RTL_TEXTENCODING_UTF8 ).getStr(), 1868 theLock->token ); 1869 1870 m_aCurlLockStore.removeLock( theLock ); 1871 ne_lock_destroy( theLock ); 1872 return true; 1873 } 1874 catch ( DAVException const & ) 1875 { 1876 } 1877 return false; 1878 */ 1879 } 1880 1881 // ------------------------------------------------------------------- 1882 // static 1883 bool 1884 CurlSession::getDataFromInputStream( 1885 const uno::Reference< io::XInputStream > & xStream, 1886 uno::Sequence< sal_Int8 > & rData, 1887 bool bAppendTrailingZeroByte ) 1888 { 1889 if ( xStream.is() ) 1890 { 1891 uno::Reference< io::XSeekable > xSeekable( xStream, uno::UNO_QUERY ); 1892 if ( xSeekable.is() ) 1893 { 1894 try 1895 { 1896 sal_Int32 nSize 1897 = sal::static_int_cast<sal_Int32>(xSeekable->getLength()); 1898 sal_Int32 nRead 1899 = xStream->readBytes( rData, nSize ); 1900 1901 if ( nRead == nSize ) 1902 { 1903 if ( bAppendTrailingZeroByte ) 1904 { 1905 rData.realloc( nSize + 1 ); 1906 rData[ nSize ] = sal_Int8( 0 ); 1907 } 1908 return true; 1909 } 1910 } 1911 catch ( io::NotConnectedException const & ) 1912 { 1913 // readBytes 1914 } 1915 catch ( io::BufferSizeExceededException const & ) 1916 { 1917 // readBytes 1918 } 1919 catch ( io::IOException const & ) 1920 { 1921 // getLength, readBytes 1922 } 1923 } 1924 else 1925 { 1926 try 1927 { 1928 uno::Sequence< sal_Int8 > aBuffer; 1929 sal_Int32 nPos = 0; 1930 1931 sal_Int32 nRead = xStream->readSomeBytes( aBuffer, 65536 ); 1932 while ( nRead > 0 ) 1933 { 1934 if ( rData.getLength() < ( nPos + nRead ) ) 1935 rData.realloc( nPos + nRead ); 1936 1937 aBuffer.realloc( nRead ); 1938 rtl_copyMemory( (void*)( rData.getArray() + nPos ), 1939 (const void*)aBuffer.getConstArray(), 1940 nRead ); 1941 nPos += nRead; 1942 1943 aBuffer.realloc( 0 ); 1944 nRead = xStream->readSomeBytes( aBuffer, 65536 ); 1945 } 1946 1947 if ( bAppendTrailingZeroByte ) 1948 { 1949 rData.realloc( nPos + 1 ); 1950 rData[ nPos ] = sal_Int8( 0 ); 1951 } 1952 return true; 1953 } 1954 catch ( io::NotConnectedException const & ) 1955 { 1956 // readBytes 1957 } 1958 catch ( io::BufferSizeExceededException const & ) 1959 { 1960 // readBytes 1961 } 1962 catch ( io::IOException const & ) 1963 { 1964 // readBytes 1965 } 1966 } 1967 } 1968 return false; 1969 } 1970 1971 // --------------------------------------------------------------------- 1972 sal_Bool 1973 CurlSession::isDomainMatch( rtl::OUString certHostName ) 1974 { 1975 rtl::OUString hostName = getHostName(); 1976 1977 if (hostName.equalsIgnoreAsciiCase( certHostName ) ) 1978 return sal_True; 1979 1980 if ( 0 == certHostName.indexOf( rtl::OUString::createFromAscii( "*" ) ) && 1981 hostName.getLength() >= certHostName.getLength() ) 1982 { 1983 rtl::OUString cmpStr = certHostName.copy( 1 ); 1984 1985 if ( hostName.matchIgnoreAsciiCase( 1986 cmpStr, hostName.getLength() - cmpStr.getLength() ) ) 1987 return sal_True; 1988 } 1989 return sal_False; 1990 } 1991