xref: /trunk/main/ucb/source/ucp/webdav/CurlSession.cxx (revision 45c5a00162811bd03b87fcb4fe9996782f2b59ec)
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