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