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