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