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 {
CredentialsDataCredentialsData67 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 // -------------------------------------------------------------------
CurlSession(const rtl::Reference<DAVSessionFactory> & rSessionFactory,const rtl::OUString & inUri,const ucbhelper::InternetProxyDecider & rProxyDecider)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 // -------------------------------------------------------------------
~CurlSession()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 // -------------------------------------------------------------------
Init(const DAVRequestEnvironment & rEnv)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 // -------------------------------------------------------------------
Init()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
isSSLNeeded()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
composeCurrentUri(const rtl::OUString & inPath)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
CanUse(const rtl::OUString & inUri)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
UsesProxy()321 sal_Bool CurlSession::UsesProxy()
322 {
323 Init();
324 return ( m_aProxyName.getLength() > 0 );
325 }
326
Curl_DebugCallback(CURL *,curl_infotype type,unsigned char * data,size_t size,void * userdata)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
curlDebugOutput(curl_infotype type,char * data,int size)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
Curl_SSLContextCallback(CURL *,void * ssl_ctx,void * userptr)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
OPENSSL_VerifyCertificate(X509_STORE_CTX * x509_ctx,void * arg)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
convertCertificateToAsn1Der(X509 * certificate)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
verifyServerX509Certificate(X509_STORE_CTX * x509StoreContext)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
verifyCertificateChain(std::vector<uno::Sequence<sal_Int8>> & asn1DerCertificates)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
Curl_ProvideCredentials(long statusCode,void * userdata)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
provideCredentials(const DAVRequestEnvironment & env,CurlRequest & request,long statusCode)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
addEnvironmentRequestHeaders(CurlRequest & curlRequest,const DAVRequestEnvironment & env)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
processResponse(CurlRequest & curlRequest,CURLcode curlCode)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
responseHeadersToDAVResource(const std::vector<CurlRequest::Header> & responseHeaders,const std::vector<::rtl::OUString> & inHeaderNames,DAVResource & ioResource)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
propfind(CurlRequest & curlRequest,const rtl::OUString & inPath,const Depth inDepth,const std::vector<::rtl::OUString> * inPropNames,const bool onlyPropertyNames,const DAVRequestEnvironment & rEnv)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
PROPFIND(const rtl::OUString & inPath,const Depth inDepth,const std::vector<rtl::OUString> & inPropNames,std::vector<DAVResource> & ioResources,const DAVRequestEnvironment & rEnv)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 // -------------------------------------------------------------------
PROPFIND(const rtl::OUString & inPath,const Depth inDepth,std::vector<DAVResourceInfo> & ioResInfo,const DAVRequestEnvironment & rEnv)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 // -------------------------------------------------------------------
PROPPATCH(const rtl::OUString & inPath,const std::vector<ProppatchValue> & inValues,const DAVRequestEnvironment & rEnv)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 // -------------------------------------------------------------------
HEAD(const::rtl::OUString & inPath,const std::vector<::rtl::OUString> & inHeaderNames,DAVResource & ioResource,const DAVRequestEnvironment & rEnv)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 >
GET(const rtl::OUString & inPath,const DAVRequestEnvironment & rEnv)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 // -------------------------------------------------------------------
GET(const rtl::OUString & inPath,uno::Reference<io::XOutputStream> & ioOutputStream,const DAVRequestEnvironment & rEnv)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 >
GET(const rtl::OUString & inPath,const std::vector<::rtl::OUString> & inHeaderNames,DAVResource & ioResource,const DAVRequestEnvironment & rEnv)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 // -------------------------------------------------------------------
GET(const rtl::OUString & inPath,uno::Reference<io::XOutputStream> & ioOutputStream,const std::vector<::rtl::OUString> & inHeaderNames,DAVResource & ioResource,const DAVRequestEnvironment & rEnv)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 // -------------------------------------------------------------------
PUT(const rtl::OUString & inPath,const uno::Reference<io::XInputStream> & inInputStream,const DAVRequestEnvironment & rEnv)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 >
POST(const rtl::OUString & inPath,const rtl::OUString & rContentType,const rtl::OUString & rReferer,const uno::Reference<io::XInputStream> & inInputStream,const DAVRequestEnvironment & rEnv)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 // -------------------------------------------------------------------
POST(const rtl::OUString & inPath,const rtl::OUString & rContentType,const rtl::OUString & rReferer,const uno::Reference<io::XInputStream> & inInputStream,uno::Reference<io::XOutputStream> & oOutputStream,const DAVRequestEnvironment & rEnv)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 // -------------------------------------------------------------------
MKCOL(const rtl::OUString & inPath,const DAVRequestEnvironment & rEnv)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 // -------------------------------------------------------------------
COPY(const rtl::OUString & inSourceURL,const rtl::OUString & inDestinationURL,const DAVRequestEnvironment & rEnv,sal_Bool inOverWrite)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 // -------------------------------------------------------------------
MOVE(const rtl::OUString & inSourceURL,const rtl::OUString & inDestinationURL,const DAVRequestEnvironment & rEnv,sal_Bool inOverWrite)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 // -------------------------------------------------------------------
DESTROY(const rtl::OUString & inPath,const DAVRequestEnvironment & rEnv)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 {
lastChanceToSendRefreshRequest(TimeValue const & rStart,sal_Int32 timeout)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 // -------------------------------------------------------------------
LOCK(const::rtl::OUString & inPath,ucb::Lock & inLock,const DAVRequestEnvironment & rEnv)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 // -------------------------------------------------------------------
LOCK(const::rtl::OUString &,sal_Int64 nTimeout,const DAVRequestEnvironment &)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 // -------------------------------------------------------------------
LOCK(CurlLock * pLock,sal_Int32 & rlastChanceToSendRefreshRequest)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 // -------------------------------------------------------------------
UNLOCK(const::rtl::OUString & inPath,const DAVRequestEnvironment & rEnv)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 // -------------------------------------------------------------------
UNLOCK(CurlLock * pLock)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 // -------------------------------------------------------------------
abort()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 // -------------------------------------------------------------------
getProxySettings() const1743 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
removeExpiredLocktoken(const rtl::OUString &,const DAVRequestEnvironment &)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
getDataFromInputStream(const uno::Reference<io::XInputStream> & xStream,uno::Sequence<sal_Int8> & rData,bool bAppendTrailingZeroByte)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
isDomainMatch(rtl::OUString certHostName)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