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