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 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_ucb.hxx"
24 
25 #include <hash_map>
26 #include <vector>
27 #include <string.h>
28 #include <rtl/string.h>
29 #include <rtl/ustrbuf.hxx>
30 #include <osl/time.h>
31 #include "comphelper/sequence.hxx"
32 #include "ucbhelper/simplecertificatevalidationrequest.hxx"
33 
34 #include "AprEnv.hxx"
35 #include <apr_strings.h>
36 
37 #include "DAVAuthListener.hxx"
38 #include "SerfTypes.hxx"
39 #include "SerfSession.hxx"
40 #include "SerfUri.hxx"
41 #include "SerfRequestProcessor.hxx"
42 #include "SerfCallbacks.hxx"
43 #include "SerfInputStream.hxx"
44 #include "UCBDeadPropertyValue.hxx"
45 
46 #include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
47 #include <com/sun/star/security/XCertificate.hpp>
48 #include <com/sun/star/security/CertificateValidity.hpp>
49 #include <com/sun/star/security/CertificateContainerStatus.hpp>
50 #include <com/sun/star/security/CertificateContainer.hpp>
51 #include <com/sun/star/security/XCertificateContainer.hpp>
52 #include <com/sun/star/security/CertAltNameEntry.hpp>
53 #include <com/sun/star/security/XSanExtension.hpp>
54 #define OID_SUBJECT_ALTERNATIVE_NAME "2.5.29.17"
55 
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 http_dav_ucp;
61 
62 // -------------------------------------------------------------------
63 // static members!
64 SerfLockStore SerfSession::m_aSerfLockStore;
65 
66 // -------------------------------------------------------------------
67 // Constructor
68 // -------------------------------------------------------------------
69 SerfSession::SerfSession(
70         const rtl::Reference< DAVSessionFactory > & rSessionFactory,
71         const rtl::OUString& inUri,
72         const ucbhelper::InternetProxyDecider & rProxyDecider )
73     throw ( DAVException )
74     : DAVSession( rSessionFactory )
75     , m_aMutex()
76     , m_aUri( inUri )
77     , m_aProxyName()
78     , m_nProxyPort( 0 )
79     , m_aServerHeaderField()
80     , m_pSerfConnection( 0 )
81     , m_pSerfContext( 0 )
82     , m_bIsHeadRequestInProgress( false )
83     , m_bUseChunkedEncoding( false )
84     , m_bNoOfTransferEncodingSwitches( 0 )
85     , m_rProxyDecider( rProxyDecider )
86     , m_aEnv()
87 {
88     m_pSerfContext = serf_context_create( getAprPool() );
89 
90     m_pSerfBucket_Alloc = serf_bucket_allocator_create( getAprPool(), NULL, NULL );
91 }
92 
93 // -------------------------------------------------------------------
94 // Destructor
95 // -------------------------------------------------------------------
96 SerfSession::~SerfSession( )
97 {
98     if ( m_pSerfConnection )
99     {
100         serf_connection_close( m_pSerfConnection );
101         m_pSerfConnection = 0;
102         OSL_TRACE("SerfSession::~SerfSession: closed serf connection");
103     }
104 }
105 
106 // -------------------------------------------------------------------
107 void SerfSession::Init( const DAVRequestEnvironment & rEnv )
108   throw ( DAVException )
109 {
110     osl::Guard< osl::Mutex > theGuard( m_aMutex );
111     m_aEnv = rEnv;
112     Init();
113 }
114 
115 // -------------------------------------------------------------------
116 void SerfSession::Init()
117     throw ( DAVException )
118 {
119     osl::Guard< osl::Mutex > theGuard( m_aMutex );
120 
121     bool bCreateNewSession = false;
122 
123     if ( m_pSerfConnection == 0 )
124     {
125         const ucbhelper::InternetProxyServer & rProxyCfg = getProxySettings();
126 
127         m_aProxyName = rProxyCfg.aName;
128         m_nProxyPort = rProxyCfg.nPort;
129 
130         // Not yet initialized. Create new session.
131         bCreateNewSession = true;
132         OSL_TRACE("SerfSession::Init: serf connection created");
133     }
134     else
135     {
136         const ucbhelper::InternetProxyServer & rProxyCfg = getProxySettings();
137 
138         if ( ( rProxyCfg.aName != m_aProxyName )
139              || ( rProxyCfg.nPort != m_nProxyPort ) )
140         {
141             m_aProxyName = rProxyCfg.aName;
142             m_nProxyPort = rProxyCfg.nPort;
143 
144             // new session needed, destroy old first
145             serf_connection_close( m_pSerfConnection );
146             m_pSerfConnection = 0;
147             bCreateNewSession = true;
148         }
149     }
150 
151     if ( bCreateNewSession )
152     {
153         // TODO - close_connection callback
154         apr_status_t status = serf_connection_create2( &m_pSerfConnection,
155                                                        m_pSerfContext,
156                                                        *(m_aUri.getAprUri()),
157                                                        Serf_ConnectSetup, this,
158                                                        0 /* close connection callback */, 0 /* close connection baton */,
159                                                        getAprPool() );
160 
161         if ( m_pSerfConnection == 0 ||status != APR_SUCCESS )
162         {
163             throw DAVException( DAVException::DAV_SESSION_CREATE,
164                                 SerfUri::makeConnectionEndPointString( m_aUri.GetHost(), m_aUri.GetPort() ) );
165         }
166 
167         // Register the session with the lock store
168 //        m_aSerfLockStore.registerSession( m_pSerfConnection );
169 
170         if ( m_aProxyName.getLength() )
171         {
172             apr_sockaddr_t *proxy_address = NULL;
173             status = apr_sockaddr_info_get( &proxy_address,
174                                                                rtl::OUStringToOString( m_aProxyName, RTL_TEXTENCODING_UTF8 ).getStr(),
175                                                                APR_UNSPEC,
176                                                                static_cast<apr_port_t>(m_nProxyPort),
177                                                                0, getAprPool() );
178 
179             if ( status != APR_SUCCESS )
180             {
181                 throw DAVException( DAVException::DAV_SESSION_CREATE,
182                                     SerfUri::makeConnectionEndPointString( m_aUri.GetHost(), m_aUri.GetPort() ) );
183             }
184 
185             serf_config_proxy( m_pSerfContext, proxy_address );
186         }
187 
188 
189         serf_config_credentials_callback( m_pSerfContext, Serf_Credentials );
190 
191         m_bUseChunkedEncoding = isSSLNeeded();
192     }
193 }
194 
195 apr_pool_t* SerfSession::getAprPool()
196 {
197     return apr_environment::AprEnv::getAprEnv()->getAprPool();
198 }
199 
200 serf_bucket_alloc_t* SerfSession::getSerfBktAlloc()
201 {
202     return m_pSerfBucket_Alloc;
203 }
204 
205 serf_context_t* SerfSession::getSerfContext()
206 {
207     return m_pSerfContext;
208 }
209 
210 SerfConnection* SerfSession::getSerfConnection()
211 {
212     return m_pSerfConnection;
213 }
214 
215 bool SerfSession::isHeadRequestInProgress()
216 {
217     return m_bIsHeadRequestInProgress;
218 }
219 
220 bool SerfSession::isSSLNeeded()
221 {
222     return m_aUri.GetScheme().equalsIgnoreAsciiCase( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "https" ) ) );
223 }
224 
225 char* SerfSession::getHostinfo()
226 {
227     return m_aUri.getAprUri()->hostinfo;
228 }
229 
230 // -------------------------------------------------------------------
231 // helper function
232 // it composes the uri for lockstore registration
233 rtl::OUString SerfSession::composeCurrentUri(const rtl::OUString & inPath)
234 {
235     rtl::OUString aScheme( m_aUri.GetScheme() );
236     rtl::OUStringBuffer aBuf( aScheme );
237     aBuf.appendAscii( "://" );
238     if ( m_aUri.GetUserInfo().getLength() > 0 )
239     {
240         aBuf.append( m_aUri.GetUserInfo() );
241         aBuf.appendAscii( "@" );
242     }
243     // Is host a numeric IPv6 address?
244     if ( ( m_aUri.GetHost().indexOf( ':' ) != -1 ) &&
245          ( m_aUri.GetHost()[ 0 ] != sal_Unicode( '[' ) ) )
246     {
247         aBuf.appendAscii( "[" );
248         aBuf.append( m_aUri.GetHost() );
249         aBuf.appendAscii( "]" );
250     }
251     else
252     {
253         aBuf.append( m_aUri.GetHost() );
254     }
255 
256     // append port, but only, if not default port.
257     bool bAppendPort = true;
258     sal_Int32 aPort = m_aUri.GetPort();
259     switch ( aPort )
260     {
261     case DEFAULT_HTTP_PORT:
262         bAppendPort = aScheme.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "http" ) );
263         break;
264 
265     case DEFAULT_HTTPS_PORT:
266         bAppendPort = !aScheme.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "https" ) );
267         break;
268     }
269     if ( bAppendPort )
270     {
271         aBuf.appendAscii( ":" );
272         aBuf.append( rtl::OUString::valueOf( aPort ) );
273     }
274     aBuf.append( inPath );
275 
276     rtl::OUString   aUri(aBuf.makeStringAndClear() );
277     return aUri;
278 }
279 
280 // -------------------------------------------------------------------
281 // virtual
282 sal_Bool SerfSession::CanUse( const rtl::OUString & inUri )
283 {
284     try
285     {
286         SerfUri theUri( inUri );
287         if ( ( theUri.GetPort() == m_aUri.GetPort() ) &&
288              ( theUri.GetHost() == m_aUri.GetHost() ) &&
289              ( theUri.GetScheme() == m_aUri.GetScheme() ) )
290         {
291             return sal_True;
292         }
293     }
294     catch ( DAVException const & )
295     {
296         return sal_False;
297     }
298     return sal_False;
299 }
300 
301 // -------------------------------------------------------------------
302 // virtual
303 sal_Bool SerfSession::UsesProxy()
304 {
305     Init();
306     return ( m_aProxyName.getLength() > 0 );
307 }
308 
309 apr_status_t SerfSession::setupSerfConnection( apr_socket_t * inAprSocket,
310                                                serf_bucket_t **outSerfInputBucket,
311                                                serf_bucket_t **outSerfOutputBucket,
312                                                apr_pool_t* /*inAprPool*/ )
313 {
314     serf_bucket_t *tmpInputBkt;
315     tmpInputBkt = serf_context_bucket_socket_create( getSerfContext(),
316                                                      inAprSocket,
317                                                      getSerfBktAlloc() );
318 
319     if ( isSSLNeeded() )
320     {
321         tmpInputBkt = serf_bucket_ssl_decrypt_create( tmpInputBkt,
322                                                       0,
323                                                       getSerfBktAlloc() );
324         /** Set the callback that is called to authenticate the
325             certifcate (chain).
326         */
327         serf_ssl_server_cert_chain_callback_set(
328             serf_bucket_ssl_decrypt_context_get(tmpInputBkt),
329             NULL,
330             Serf_CertificateChainValidation,
331             this);
332         serf_ssl_set_hostname( serf_bucket_ssl_decrypt_context_get( tmpInputBkt ),
333                                getHostinfo() );
334 
335         *outSerfOutputBucket = serf_bucket_ssl_encrypt_create( *outSerfOutputBucket,
336                                                                serf_bucket_ssl_decrypt_context_get( tmpInputBkt ),
337                                                                getSerfBktAlloc() );
338     }
339 
340     *outSerfInputBucket = tmpInputBkt;
341 
342     return APR_SUCCESS;
343 }
344 
345 apr_status_t SerfSession::provideSerfCredentials( bool bGiveProvidedCredentialsASecondTry,
346                                                   char ** outUsername,
347                                                   char ** outPassword,
348                                                   serf_request_t * /*inRequest*/,
349                                                   int /*inCode*/,
350                                                   const char *inAuthProtocol,
351                                                   const char *inRealm,
352                                                   apr_pool_t *inAprPool )
353 {
354     DAVAuthListener * pListener = getRequestEnvironment().m_xAuthListener.get();
355     if ( !pListener )
356     {
357         // abort
358         return SERF_ERROR_AUTHN_FAILED;
359     }
360 
361     rtl::OUString theUserName;
362     rtl::OUString thePassWord;
363     try
364     {
365         SerfUri uri( getRequestEnvironment().m_aRequestURI );
366         rtl::OUString aUserInfo( uri.GetUserInfo() );
367         if ( aUserInfo.getLength() )
368         {
369             sal_Int32 nPos = aUserInfo.indexOf( '@' );
370             if ( nPos == -1 )
371             {
372                 theUserName = aUserInfo;
373             }
374             else
375             {
376                 theUserName = aUserInfo.copy( 0, nPos );
377                 thePassWord = aUserInfo.copy( nPos + 1 );
378             }
379         }
380     }
381     catch ( DAVException const & )
382     {
383         // abort
384         return SERF_ERROR_AUTHN_FAILED;
385     }
386 
387     const bool bCanUseSystemCreds = ( ( strcasecmp( inAuthProtocol, "NTLM" ) == 0 ) ||
388                                       ( strcasecmp( inAuthProtocol, "Negotiate" ) == 0 ) );
389 
390     int theRetVal = pListener->authenticate( rtl::OUString::createFromAscii( inRealm ),
391                                              getHostName(),
392                                              theUserName,
393                                              thePassWord,
394                                              bCanUseSystemCreds,
395                                              bGiveProvidedCredentialsASecondTry ? sal_False : sal_True );
396 
397     if ( theRetVal == 0 )
398     {
399         *outUsername = apr_pstrdup( inAprPool, rtl::OUStringToOString( theUserName, RTL_TEXTENCODING_UTF8 ).getStr() );
400         *outPassword = apr_pstrdup( inAprPool, rtl::OUStringToOString( thePassWord, RTL_TEXTENCODING_UTF8 ).getStr() );
401     }
402 
403     return theRetVal != 0 ? SERF_ERROR_AUTHN_FAILED : APR_SUCCESS;
404 }
405 
406 namespace {
407     // -------------------------------------------------------------------
408     // Helper function
409     ::rtl::OUString GetHostnamePart( const ::rtl::OUString& _rRawString )
410     {
411         ::rtl::OUString sPart;
412         ::rtl::OUString sPartId = ::rtl::OUString::createFromAscii( "CN=" );
413         sal_Int32 nContStart = _rRawString.indexOf( sPartId );
414         if ( nContStart != -1 )
415         {
416             nContStart = nContStart + sPartId.getLength();
417             sal_Int32 nContEnd
418                 = _rRawString.indexOf( sal_Unicode( ',' ), nContStart );
419             sPart = _rRawString.copy( nContStart, nContEnd - nContStart );
420         }
421         return sPart;
422     }
423 } // namespace
424 
425 
426 apr_status_t SerfSession::verifySerfCertificateChain (
427     int,
428     const serf_ssl_certificate_t * const * pCertificateChainBase64Encoded,
429     int nCertificateChainLength)
430 {
431     // Check arguments.
432     if (pCertificateChainBase64Encoded == NULL || nCertificateChainLength<=0)
433     {
434         OSL_ASSERT(pCertificateChainBase64Encoded != NULL);
435         OSL_ASSERT(nCertificateChainLength>0);
436         return SERF_SSL_CERT_UNKNOWN_FAILURE;
437     }
438 
439     // Create some crypto objects to decode and handle the base64
440     // encoded certificate chain.
441     uno::Reference< xml::crypto::XSEInitializer > xSEInitializer;
442     uno::Reference< security::XCertificateContainer > xCertificateContainer;
443     uno::Reference< xml::crypto::XXMLSecurityContext > xSecurityContext;
444     uno::Reference< xml::crypto::XSecurityEnvironment > xSecurityEnv;
445     try
446     {
447         // Create a certificate container.
448         xCertificateContainer = uno::Reference< security::XCertificateContainer >(
449             getMSF()->createInstance(
450                 rtl::OUString::createFromAscii(
451                     "com.sun.star.security.CertificateContainer" ) ),
452             uno::UNO_QUERY_THROW);
453 
454         xSEInitializer = uno::Reference< xml::crypto::XSEInitializer >(
455             getMSF()->createInstance(
456                 rtl::OUString::createFromAscii( "com.sun.star.xml.crypto.SEInitializer" ) ),
457             uno::UNO_QUERY_THROW);
458 
459         xSecurityContext = xSEInitializer->createSecurityContext( rtl::OUString() );
460         if (xSecurityContext.is())
461             xSecurityEnv = xSecurityContext->getSecurityEnvironment();
462 
463         if ( ! xSecurityContext.is() || ! xSecurityEnv.is())
464         {
465             // Do we have to dispose xSEInitializer or xCertificateContainer?
466             return SERF_SSL_CERT_UNKNOWN_FAILURE;
467         }
468     }
469     catch ( uno::Exception const &)
470     {
471         return SERF_SSL_CERT_UNKNOWN_FAILURE;
472     }
473 
474     // Decode the server certificate.
475     const char* sBase64EncodedServerCertificate (
476         serf_ssl_cert_export(
477             pCertificateChainBase64Encoded[0],
478             getAprPool()));
479     uno::Reference< security::XCertificate > xServerCertificate(
480         xSecurityEnv->createCertificateFromAscii(
481             rtl::OUString::createFromAscii(sBase64EncodedServerCertificate)));
482     if ( ! xServerCertificate.is())
483         return SERF_SSL_CERT_UNKNOWN_FAILURE;
484 
485     // Get the subject from the server certificate.
486     ::rtl::OUString sServerCertificateSubject (xServerCertificate->getSubjectName());
487     sal_Int32 nIndex = 0;
488     while (nIndex >= 0)
489     {
490         const ::rtl::OUString sToken (sServerCertificateSubject.getToken(0, ',', nIndex));
491         if (sToken.compareToAscii("CN=", 3) == 0)
492         {
493             sServerCertificateSubject = sToken.copy(3);
494             break;
495         }
496         else if (sToken.compareToAscii(" CN=", 4) == 0)
497         {
498             sServerCertificateSubject = sToken.copy(4);
499             break;
500         }
501     }
502 
503     // When the certificate container already contains a (trusted)
504     // entry for the server then we do not have to authenticate any
505     // certificate.
506     const security::CertificateContainerStatus eStatus (
507         xCertificateContainer->hasCertificate(
508             getHostName(), sServerCertificateSubject ) );
509     if (eStatus != security::CertificateContainerStatus_NOCERT)
510     {
511         return eStatus == security::CertificateContainerStatus_TRUSTED
512                ? APR_SUCCESS
513                : SERF_SSL_CERT_UNKNOWN_FAILURE;
514     }
515 
516     // The shortcut failed, so try to verify the whole chain.  This is
517     // done outside the isDomainMatch() block because the result is
518     // used by the interaction handler.
519     std::vector< uno::Reference< security::XCertificate > > aChain;
520     for (nIndex=1; nIndex<nCertificateChainLength; ++nIndex)
521     {
522         const char* sBase64EncodedCertificate (
523             serf_ssl_cert_export(
524                 pCertificateChainBase64Encoded[nIndex],
525                 getAprPool()));
526         uno::Reference< security::XCertificate > xCertificate(
527             xSecurityEnv->createCertificateFromAscii(
528                 rtl::OUString::createFromAscii(sBase64EncodedCertificate)));
529         if ( ! xCertificate.is())
530             return SERF_SSL_CERT_UNKNOWN_FAILURE;
531         aChain.push_back(xCertificate);
532     }
533     const sal_Int64 nVerificationResult (xSecurityEnv->verifyCertificate(
534             xServerCertificate,
535             ::comphelper::containerToSequence(aChain)));
536 
537     // When the certificate matches the host name then we can use the
538     // result of the verification.
539     bool bHostnameMatchesCertHostnames = false;
540     {
541         uno::Sequence< uno::Reference< security::XCertificateExtension > > extensions = xServerCertificate->getExtensions();
542         uno::Sequence< security::CertAltNameEntry > altNames;
543         for (sal_Int32 i = 0 ; i < extensions.getLength(); ++i)
544         {
545             uno::Reference< security::XCertificateExtension >element = extensions[i];
546 
547             const rtl::OString aId ( (const sal_Char *)element->getExtensionId().getArray(), element->getExtensionId().getLength());
548             if ( aId.equals( OID_SUBJECT_ALTERNATIVE_NAME ) )
549             {
550                 uno::Reference< security::XSanExtension > sanExtension ( element, uno::UNO_QUERY );
551                 altNames =  sanExtension->getAlternativeNames();
552                 break;
553             }
554         }
555 
556         uno::Sequence< ::rtl::OUString > certHostNames(altNames.getLength() + 1);
557         certHostNames[0] = sServerCertificateSubject;
558         for( int n = 0; n < altNames.getLength(); ++n )
559         {
560             if (altNames[n].Type ==  security::ExtAltNameType_DNS_NAME)
561             {
562                 altNames[n].Value >>= certHostNames[n+1];
563             }
564         }
565 
566         for ( int i = 0; i < certHostNames.getLength() && !bHostnameMatchesCertHostnames; ++i )
567         {
568             bHostnameMatchesCertHostnames = isDomainMatch( certHostNames[i] );
569         }
570 
571     }
572     if ( bHostnameMatchesCertHostnames )
573     {
574 
575         if (nVerificationResult == 0)
576         {
577             // Certificate (chain) is valid.
578             xCertificateContainer->addCertificate(getHostName(), sServerCertificateSubject,  sal_True);
579             return APR_SUCCESS;
580         }
581         else if ((nVerificationResult & security::CertificateValidity::CHAIN_INCOMPLETE) != 0)
582         {
583             // We do not have enough information for verification,
584             // neither automatically (as we just discovered) nor
585             // manually (so there is no point in showing any dialog.)
586             return SERF_SSL_CERT_UNKNOWN_FAILURE;
587         }
588         else if ((nVerificationResult &
589                 (security::CertificateValidity::INVALID | security::CertificateValidity::REVOKED)) != 0)
590         {
591             // Certificate (chain) is invalid.
592             xCertificateContainer->addCertificate(getHostName(), sServerCertificateSubject,  sal_False);
593             return SERF_SSL_CERT_UNKNOWN_FAILURE;
594         }
595         else
596         {
597             // For all other we have to ask the user.
598         }
599     }
600 
601     // We have not been able to automatically verify (or falsify) the
602     // certificate chain.  To resolve this we have to ask the user.
603     const uno::Reference< ucb::XCommandEnvironment > xEnv( getRequestEnvironment().m_xEnv );
604     if ( xEnv.is() )
605     {
606         uno::Reference< task::XInteractionHandler > xIH( xEnv->getInteractionHandler() );
607         if ( xIH.is() )
608         {
609             rtl::Reference< ucbhelper::SimpleCertificateValidationRequest >
610                 xRequest( new ucbhelper::SimpleCertificateValidationRequest(
611                         static_cast<sal_Int32>(nVerificationResult), xServerCertificate, getHostName() ) );
612             xIH->handle( xRequest.get() );
613 
614             rtl::Reference< ucbhelper::InteractionContinuation > xSelection
615                 = xRequest->getSelection();
616 
617             if ( xSelection.is() )
618             {
619                 uno::Reference< task::XInteractionApprove > xApprove( xSelection.get(), uno::UNO_QUERY );
620                 if ( xApprove.is() )
621                 {
622                     xCertificateContainer->addCertificate( getHostName(), sServerCertificateSubject,  sal_True );
623                     return APR_SUCCESS;
624                 }
625                 else
626                 {
627                     // Don't trust cert
628                     xCertificateContainer->addCertificate( getHostName(), sServerCertificateSubject, sal_False );
629                     return SERF_SSL_CERT_UNKNOWN_FAILURE;
630                 }
631             }
632         }
633         else
634         {
635             // Don't trust cert
636             xCertificateContainer->addCertificate( getHostName(), sServerCertificateSubject, sal_False );
637             return SERF_SSL_CERT_UNKNOWN_FAILURE;
638         }
639     }
640 
641     return SERF_SSL_CERT_UNKNOWN_FAILURE;
642 }
643 
644 serf_bucket_t* SerfSession::acceptSerfResponse( serf_request_t * inSerfRequest,
645                                                 serf_bucket_t * inSerfStreamBucket,
646                                                 apr_pool_t* /*inAprPool*/ )
647 {
648     // get the per-request bucket allocator
649     serf_bucket_alloc_t* SerfBktAlloc = serf_request_get_alloc( inSerfRequest );
650 
651     // create a barrier bucket so the response doesn't eat us!
652     serf_bucket_t *responseBkt = serf_bucket_barrier_create( inSerfStreamBucket,
653                                                              SerfBktAlloc );
654 
655     // create response bucket
656     responseBkt = serf_bucket_response_create( responseBkt,
657                                                SerfBktAlloc );
658 
659     if ( isHeadRequestInProgress() )
660     {
661         // advise the response bucket that this was from a HEAD request and that it should not expect to see a response body.
662         serf_bucket_response_set_head( responseBkt );
663     }
664 
665     return responseBkt;
666 }
667 
668 SerfRequestProcessor* SerfSession::createReqProc( const rtl::OUString & inPath )
669 {
670     return new SerfRequestProcessor( *this,
671                                      inPath,
672                                      m_bUseChunkedEncoding );
673 }
674 
675 // -------------------------------------------------------------------
676 // PROPFIND - allprop & named
677 // -------------------------------------------------------------------
678 void SerfSession::PROPFIND( const rtl::OUString & inPath,
679                             const Depth inDepth,
680                             const std::vector< rtl::OUString > & inPropNames,
681                             std::vector< DAVResource > & ioResources,
682                             const DAVRequestEnvironment & rEnv )
683     throw ( DAVException )
684 {
685     osl::Guard< osl::Mutex > theGuard( m_aMutex );
686 
687     Init( rEnv );
688 
689     apr_status_t status = APR_SUCCESS;
690     boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) );
691     aReqProc->processPropFind( inDepth,
692                                inPropNames,
693                                ioResources,
694                                status );
695 
696     if ( status == APR_SUCCESS &&
697          aReqProc->mpDAVException == 0 &&
698          ioResources.empty() )
699     {
700         m_aEnv = DAVRequestEnvironment();
701         throw DAVException( DAVException::DAV_HTTP_ERROR, inPath, (sal_uInt16)APR_EGENERAL );
702     }
703     HandleError( aReqProc );
704 }
705 
706 // -------------------------------------------------------------------
707 // PROPFIND - propnames
708 // -------------------------------------------------------------------
709 void SerfSession::PROPFIND( const rtl::OUString & inPath,
710                             const Depth inDepth,
711                             std::vector< DAVResourceInfo > & ioResInfo,
712                             const DAVRequestEnvironment & rEnv )
713     throw( DAVException )
714 {
715     osl::Guard< osl::Mutex > theGuard( m_aMutex );
716 
717     Init( rEnv );
718 
719     apr_status_t status = APR_SUCCESS;
720     boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) );
721     aReqProc->processPropFind( inDepth,
722                                ioResInfo,
723                                status );
724 
725     if ( status == APR_SUCCESS &&
726          aReqProc->mpDAVException == 0 &&
727          ioResInfo.empty() )
728     {
729         m_aEnv = DAVRequestEnvironment();
730         throw DAVException( DAVException::DAV_HTTP_ERROR, inPath, (sal_uInt16)APR_EGENERAL );
731     }
732     HandleError( aReqProc );
733 }
734 
735 // -------------------------------------------------------------------
736 // PROPPATCH
737 // -------------------------------------------------------------------
738 void SerfSession::PROPPATCH( const rtl::OUString & inPath,
739                              const std::vector< ProppatchValue > & inValues,
740                              const DAVRequestEnvironment & rEnv )
741     throw( DAVException )
742 {
743     osl::Guard< osl::Mutex > theGuard( m_aMutex );
744 
745     Init( rEnv );
746 
747     apr_status_t status = APR_SUCCESS;
748     boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) );
749     //check whether a lock on this resource is already owned
750     rtl::OUString aUri( composeCurrentUri( inPath ) );
751     ucb::Lock inLock;
752     SerfLock * pLock = m_aSerfLockStore.findByUri( aUri );
753     if ( pLock )
754     {
755         inLock = pLock->getLock();
756     }
757     aReqProc->processPropPatch( inValues,
758                                 inLock,
759                                 status );
760 
761     HandleError( aReqProc );
762 }
763 
764 // -------------------------------------------------------------------
765 // HEAD
766 // -------------------------------------------------------------------
767 void SerfSession::HEAD( const ::rtl::OUString & inPath,
768                         const std::vector< ::rtl::OUString > & inHeaderNames,
769                         DAVResource & ioResource,
770                         const DAVRequestEnvironment & rEnv )
771     throw( DAVException )
772 {
773     osl::Guard< osl::Mutex > theGuard( m_aMutex );
774 
775     Init( rEnv );
776 
777     m_bIsHeadRequestInProgress = true;
778 
779     boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) );
780     ioResource.uri = inPath;
781     ioResource.properties.clear();
782     apr_status_t status = APR_SUCCESS;
783     aReqProc->processHead( inHeaderNames,
784                            ioResource,
785                            status );
786 
787     m_bIsHeadRequestInProgress = false;
788 
789     HandleError( aReqProc );
790 }
791 
792 // -------------------------------------------------------------------
793 // GET
794 // -------------------------------------------------------------------
795 uno::Reference< io::XInputStream >
796 SerfSession::GET( const rtl::OUString & inPath,
797                   const DAVRequestEnvironment & rEnv )
798     throw ( DAVException )
799 {
800     osl::Guard< osl::Mutex > theGuard( m_aMutex );
801 
802     Init( rEnv );
803 
804     uno::Reference< SerfInputStream > xInputStream( new SerfInputStream );
805     apr_status_t status = APR_SUCCESS;
806     boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) );
807     aReqProc->processGet( xInputStream,
808                           status );
809 
810     HandleError( aReqProc );
811 
812     return uno::Reference< io::XInputStream >( xInputStream.get() );
813 }
814 
815 // -------------------------------------------------------------------
816 // GET
817 // -------------------------------------------------------------------
818 void SerfSession::GET( const rtl::OUString & inPath,
819                        uno::Reference< io::XOutputStream > & ioOutputStream,
820                        const DAVRequestEnvironment & rEnv )
821     throw ( DAVException )
822 {
823     osl::Guard< osl::Mutex > theGuard( m_aMutex );
824 
825     Init( rEnv );
826 
827     apr_status_t status = APR_SUCCESS;
828     boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) );
829     aReqProc->processGet( ioOutputStream,
830                           status );
831 
832     HandleError( aReqProc );
833 }
834 
835 // -------------------------------------------------------------------
836 // GET
837 // -------------------------------------------------------------------
838 uno::Reference< io::XInputStream >
839 SerfSession::GET( const rtl::OUString & inPath,
840                   const std::vector< ::rtl::OUString > & inHeaderNames,
841                   DAVResource & ioResource,
842                   const DAVRequestEnvironment & rEnv )
843     throw ( DAVException )
844 {
845     osl::Guard< osl::Mutex > theGuard( m_aMutex );
846 
847     Init( rEnv );
848 
849     boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) );
850     uno::Reference< SerfInputStream > xInputStream( new SerfInputStream );
851     ioResource.uri = inPath;
852     ioResource.properties.clear();
853     apr_status_t status = APR_SUCCESS;
854     aReqProc->processGet( xInputStream,
855                           inHeaderNames,
856                           ioResource,
857                           status );
858 
859     HandleError( aReqProc );
860 
861     return uno::Reference< io::XInputStream >( xInputStream.get() );
862 }
863 
864 
865 // -------------------------------------------------------------------
866 // GET
867 // -------------------------------------------------------------------
868 void SerfSession::GET( const rtl::OUString & inPath,
869                        uno::Reference< io::XOutputStream > & ioOutputStream,
870                        const std::vector< ::rtl::OUString > & inHeaderNames,
871                        DAVResource & ioResource,
872                        const DAVRequestEnvironment & rEnv )
873     throw ( DAVException )
874 {
875     osl::Guard< osl::Mutex > theGuard( m_aMutex );
876 
877     Init( rEnv );
878 
879     boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) );
880     ioResource.uri = inPath;
881     ioResource.properties.clear();
882     apr_status_t status = APR_SUCCESS;
883     aReqProc->processGet( ioOutputStream,
884                           inHeaderNames,
885                           ioResource,
886                           status );
887 
888     HandleError( aReqProc );
889 }
890 
891 // -------------------------------------------------------------------
892 // PUT
893 // -------------------------------------------------------------------
894 void SerfSession::PUT( const rtl::OUString & inPath,
895                        const uno::Reference< io::XInputStream > & inInputStream,
896                        const DAVRequestEnvironment & rEnv )
897     throw ( DAVException )
898 {
899     osl::Guard< osl::Mutex > theGuard( m_aMutex );
900 
901     Init( rEnv );
902 
903     boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) );
904     uno::Sequence< sal_Int8 > aDataToSend;
905     if ( !getDataFromInputStream( inInputStream, aDataToSend, false ) )
906         throw DAVException( DAVException::DAV_INVALID_ARG );
907     apr_status_t status = APR_SUCCESS;
908 
909     //check whether a lock on this resource is already owned
910     rtl::OUString aUri( composeCurrentUri( inPath ) );
911     ucb::Lock inLock;
912     SerfLock * pLock = m_aSerfLockStore.findByUri( aUri );
913     if ( pLock )
914     {
915         inLock = pLock->getLock();
916     }
917     aReqProc->processPut( reinterpret_cast< const char * >( aDataToSend.getConstArray() ),
918                           aDataToSend.getLength(),
919                           inLock,
920                           status );
921 
922     HandleError( aReqProc );
923 }
924 
925 // -------------------------------------------------------------------
926 // POST
927 // -------------------------------------------------------------------
928 uno::Reference< io::XInputStream >
929 SerfSession::POST( const rtl::OUString & inPath,
930                    const rtl::OUString & rContentType,
931                    const rtl::OUString & rReferer,
932                    const uno::Reference< io::XInputStream > & inInputStream,
933                    const DAVRequestEnvironment & rEnv )
934     throw ( DAVException )
935 {
936     osl::Guard< osl::Mutex > theGuard( m_aMutex );
937 
938     uno::Sequence< sal_Int8 > aDataToSend;
939     if ( !getDataFromInputStream( inInputStream, aDataToSend, true ) )
940     {
941         throw DAVException( DAVException::DAV_INVALID_ARG );
942     }
943 
944     Init( rEnv );
945 
946     boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) );
947     uno::Reference< SerfInputStream > xInputStream( new SerfInputStream );
948     apr_status_t status = APR_SUCCESS;
949     //check whether a lock on this resource is already owned
950     rtl::OUString aUri( composeCurrentUri( inPath ) );
951     ucb::Lock inLock;
952     SerfLock * pLock = m_aSerfLockStore.findByUri( aUri );
953     if ( pLock )
954     {
955         inLock = pLock->getLock();
956     }
957     aReqProc->processPost( reinterpret_cast< const char * >( aDataToSend.getConstArray() ),
958                            aDataToSend.getLength(),
959                            rContentType,
960                            rReferer,
961                            inLock,
962                            xInputStream,
963                            status );
964 
965     HandleError( aReqProc );
966     return uno::Reference< io::XInputStream >( xInputStream.get() );
967 }
968 
969 // -------------------------------------------------------------------
970 // POST
971 // -------------------------------------------------------------------
972 void SerfSession::POST( const rtl::OUString & inPath,
973                         const rtl::OUString & rContentType,
974                         const rtl::OUString & rReferer,
975                         const uno::Reference< io::XInputStream > & inInputStream,
976                         uno::Reference< io::XOutputStream > & oOutputStream,
977                         const DAVRequestEnvironment & rEnv )
978     throw ( DAVException )
979 {
980     osl::Guard< osl::Mutex > theGuard( m_aMutex );
981 
982     uno::Sequence< sal_Int8 > aDataToSend;
983     if ( !getDataFromInputStream( inInputStream, aDataToSend, true ) )
984     {
985         throw DAVException( DAVException::DAV_INVALID_ARG );
986     }
987 
988     Init( rEnv );
989 
990     boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) );
991     apr_status_t status = APR_SUCCESS;
992     //check whether a lock on this resource is already owned
993     rtl::OUString aUri( composeCurrentUri( inPath ) );
994     ucb::Lock inLock;
995     SerfLock * pLock = m_aSerfLockStore.findByUri( aUri );
996     if ( pLock )
997     {
998         inLock = pLock->getLock();
999     }
1000     aReqProc->processPost( reinterpret_cast< const char * >( aDataToSend.getConstArray() ),
1001                            aDataToSend.getLength(),
1002                            rContentType,
1003                            rReferer,
1004                            inLock,
1005                            oOutputStream,
1006                            status );
1007 
1008     HandleError( aReqProc );
1009 }
1010 
1011 // -------------------------------------------------------------------
1012 // MKCOL
1013 // -------------------------------------------------------------------
1014 void SerfSession::MKCOL( const rtl::OUString & inPath,
1015                          const DAVRequestEnvironment & rEnv )
1016     throw ( DAVException )
1017 {
1018     osl::Guard< osl::Mutex > theGuard( m_aMutex );
1019 
1020     Init( rEnv );
1021 
1022     boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) );
1023     apr_status_t status = APR_SUCCESS;
1024     //check whether a lock on the destination resource is already owned
1025     rtl::OUString aUri( composeCurrentUri( inPath ) );
1026     ucb::Lock inLock;
1027     SerfLock * pLock = m_aSerfLockStore.findByUri( aUri );
1028     if ( pLock )
1029     {
1030         inLock = pLock->getLock();
1031     }
1032     aReqProc->processMkCol( inLock, status );
1033 
1034     HandleError( aReqProc );
1035 }
1036 
1037 // -------------------------------------------------------------------
1038 // COPY
1039 // -------------------------------------------------------------------
1040 void SerfSession::COPY( const rtl::OUString & inSourceURL,
1041                         const rtl::OUString & inDestinationURL,
1042                         const DAVRequestEnvironment & rEnv,
1043                         sal_Bool inOverWrite )
1044     throw ( DAVException )
1045 {
1046     osl::Guard< osl::Mutex > theGuard( m_aMutex );
1047 
1048     Init( rEnv );
1049 
1050     SerfUri theSourceUri( inSourceURL );
1051     boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( theSourceUri.GetPath() ) );
1052     apr_status_t status = APR_SUCCESS;
1053     //check whether a lock on the destination resource is already owned
1054     rtl::OUString aUri( composeCurrentUri( inDestinationURL ) );
1055     ucb::Lock inLock;
1056     SerfLock * pLock = m_aSerfLockStore.findByUri( aUri );
1057     if ( pLock )
1058     {
1059         inLock = pLock->getLock();
1060     }
1061     aReqProc->processCopy( inDestinationURL,
1062                            (inOverWrite ? true : false),
1063                            inLock,
1064                            status );
1065 
1066     HandleError( aReqProc );
1067 }
1068 
1069 // -------------------------------------------------------------------
1070 // MOVE
1071 // -------------------------------------------------------------------
1072 void SerfSession::MOVE( const rtl::OUString & inSourceURL,
1073                         const rtl::OUString & inDestinationURL,
1074                         const DAVRequestEnvironment & rEnv,
1075                         sal_Bool inOverWrite )
1076     throw ( DAVException )
1077 {
1078     osl::Guard< osl::Mutex > theGuard( m_aMutex );
1079 
1080     Init( rEnv );
1081 
1082     SerfUri theSourceUri( inSourceURL );
1083     boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( theSourceUri.GetPath() ) );
1084     apr_status_t status = APR_SUCCESS;
1085     //check whether a lock on the destination resource is already owned
1086     rtl::OUString aUri( composeCurrentUri( inDestinationURL ) );
1087     ucb::Lock inLock;
1088     SerfLock * pLock = m_aSerfLockStore.findByUri( aUri );
1089     if ( pLock )
1090     {
1091         inLock = pLock->getLock();
1092     }
1093     aReqProc->processMove( inDestinationURL,
1094                            (inOverWrite ? true : false),
1095                            inLock,
1096                            status );
1097 
1098     HandleError( aReqProc );
1099 }
1100 
1101 // -------------------------------------------------------------------
1102 // DESTROY
1103 // -------------------------------------------------------------------
1104 void SerfSession::DESTROY( const rtl::OUString & inPath,
1105                            const DAVRequestEnvironment & rEnv )
1106     throw ( DAVException )
1107 {
1108     osl::Guard< osl::Mutex > theGuard( m_aMutex );
1109 
1110     Init( rEnv );
1111 
1112     boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) );
1113     apr_status_t status = APR_SUCCESS;
1114     //check whether a lock on this resource is already owned
1115     rtl::OUString aUri( composeCurrentUri( inPath ) );
1116     ucb::Lock inLock;
1117     SerfLock * pLock = m_aSerfLockStore.findByUri( aUri );
1118     if ( pLock )
1119     {
1120         inLock = pLock->getLock();
1121     }
1122     aReqProc->processDelete( inLock, status );
1123 
1124     HandleError( aReqProc );
1125 }
1126 
1127 // -------------------------------------------------------------------
1128 
1129 namespace
1130 {
1131     sal_Int32 lastChanceToSendRefreshRequest( TimeValue const & rStart,
1132                                               sal_Int32 timeout )
1133     {
1134         TimeValue aEnd;
1135         osl_getSystemTime( &aEnd );
1136 
1137         // Try to estimate a safe absolute time for sending the
1138         // lock refresh request.
1139         sal_Int32 lastChanceToSendRefreshRequest = DAVINFINITY;
1140         if ( timeout != DAVINFINITY )
1141         {
1142             sal_Int32 calltime = aEnd.Seconds - rStart.Seconds;
1143             if ( calltime <= timeout )
1144             {
1145                 lastChanceToSendRefreshRequest
1146                     = aEnd.Seconds + timeout - calltime;
1147             }
1148             else
1149             {
1150                 OSL_TRACE( "No chance to refresh lock before timeout!" );
1151             }
1152         }
1153         return lastChanceToSendRefreshRequest;
1154     }
1155 
1156 } // namespace
1157 
1158 // -------------------------------------------------------------------
1159 // LOCK (set new lock)
1160 // -------------------------------------------------------------------
1161 void SerfSession::LOCK( const ::rtl::OUString & inPath,
1162                         ucb::Lock & rLock,
1163                         const DAVRequestEnvironment & rEnv )
1164     throw ( DAVException )
1165 {
1166     osl::Guard< osl::Mutex > theGuard( m_aMutex );
1167 
1168     //before locking, search in the lock store if we already own a lock for this resource
1169     //if present, return with exception DAV_LOCKED_SELF
1170     rtl::OUString   aUri( composeCurrentUri( inPath ) );
1171     SerfLock * pLock = m_aSerfLockStore.findByUri( aUri );
1172     if ( pLock )
1173     {
1174 //already present, meaning already locked by the same AOO session and already in the lockstore
1175 //just return, nothing to do
1176         return;
1177     }
1178 
1179     Init( rEnv );
1180 
1181     boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) );
1182     apr_status_t status = APR_SUCCESS;
1183 
1184     //the returned property, a sequence of locks
1185     //only the first is used
1186     DAVPropertyValue outLock;
1187 
1188     TimeValue startCall;
1189     osl_getSystemTime( &startCall );
1190     aReqProc->processLock(inPath, rLock, outLock, status);
1191 
1192     //HandleError will handle the error and throw an exception, if needed
1193     HandleError( aReqProc );
1194 
1195     if(outLock.Name.compareToAscii(RTL_CONSTASCII_STRINGPARAM( "DAV:lockdiscovery" )) == 0 )
1196     {
1197         //got a lock, use only the first returned
1198         uno::Sequence< ucb::Lock >      aLocks;
1199         outLock.Value >>= aLocks;
1200         ucb::Lock aLock = aLocks[0];
1201 
1202         SerfLock* aNewLock = new SerfLock( aLock, aUri, inPath );
1203         // add the store the new lock
1204         m_aSerfLockStore.addLock(aNewLock,this,
1205                                  lastChanceToSendRefreshRequest(
1206                                      startCall, static_cast< sal_Int32 >(aLock.Timeout) ) );
1207     }
1208 
1209 }
1210 
1211 // -------------------------------------------------------------------
1212 // LOCK (refresh existing lock from DAVResourceAccess)
1213 // -------------------------------------------------------------------
1214 sal_Int64 SerfSession::LOCK( const ::rtl::OUString & /*inPath*/,
1215                              sal_Int64 nTimeout,
1216                              const DAVRequestEnvironment & /*rEnv*/ )
1217     throw ( DAVException )
1218 {
1219     osl::Guard< osl::Mutex > theGuard( m_aMutex );
1220 
1221     return nTimeout;
1222     /*
1223     // Try to get the neon lock from lock store
1224     SerfLock * theLock
1225         = m_aSerfLockStore.findByUri( makeAbsoluteURL( inPath ) );
1226     if ( !theLock )
1227          throw DAVException( DAVException::DAV_NOT_LOCKED );
1228 
1229     Init( rEnv );
1230 
1231     // refresh existing lock.
1232     theLock->timeout = static_cast< long >( nTimeout );
1233 
1234     TimeValue startCall;
1235     osl_getSystemTime( &startCall );
1236 
1237     int theRetVal = ne_lock_refresh( m_pHttpSession, theLock );
1238 
1239     if ( theRetVal == NE_OK )
1240     {
1241         m_aSerfLockStore.updateLock( theLock,
1242                                      lastChanceToSendRefreshRequest(
1243                                          startCall, theLock->timeout ) );
1244     }
1245 
1246     HandleError( theRetVal, inPath, rEnv );
1247 
1248     return theLock->timeout;
1249     */
1250 }
1251 
1252 // -------------------------------------------------------------------
1253 // LOCK (refresh existing lock from SerfLockStore)
1254 // -------------------------------------------------------------------
1255 bool SerfSession::LOCK( SerfLock * pLock,
1256                         sal_Int32 & rlastChanceToSendRefreshRequest )
1257 {
1258     osl::Guard< osl::Mutex > theGuard( m_aMutex );
1259     rtl::OUString inPath = pLock->getResourcePath();
1260 
1261     boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) );
1262     apr_status_t status = APR_SUCCESS;
1263 
1264     //the returned property, a sequence of locks
1265     //only the first is used
1266     DAVPropertyValue outLock;
1267 
1268     TimeValue startCall;
1269     osl_getSystemTime( &startCall );
1270 
1271     // refresh existing lock.
1272     aReqProc->processLockRefresh( inPath, pLock->getLock(), outLock, status);
1273 
1274     // TODO: possible enhancement as the following:
1275     // - use an interaction handler to alert the user if the lock was not refreshed,
1276     //   offering to try again with a new session, asking the user for credential, if necessary.
1277     //   This may happen if the WebDAV server goes off-line for whatever reason, or the connection is dropped for time-out
1278     //   To implement this behavior, some redesigning of the current session implementation may be needed.
1279     //
1280 
1281     //HandleError will handle the error and throw an exception, if needed
1282     HandleError( aReqProc );
1283 
1284     uno::Sequence< ucb::Lock >      aLocks;
1285     outLock.Value >>= aLocks;
1286     ucb::Lock aLock = aLocks[0];
1287 
1288     //if ok, udate the lastchance refresh time in lock
1289     rlastChanceToSendRefreshRequest
1290         = lastChanceToSendRefreshRequest( startCall, static_cast< sal_Int32 >(aLock.Timeout) );
1291 
1292     return true;
1293 }
1294 
1295 // -------------------------------------------------------------------
1296 // UNLOCK called from external (DAVResourceAccess)
1297 // -------------------------------------------------------------------
1298 void SerfSession::UNLOCK( const ::rtl::OUString & inPath,
1299                           const DAVRequestEnvironment & rEnv )
1300     throw ( DAVException )
1301 {
1302     osl::Guard< osl::Mutex > theGuard( m_aMutex );
1303 
1304     rtl::OUString aUri( composeCurrentUri( inPath ) );
1305     SerfLock * pLock = m_aSerfLockStore.findByUri( aUri );
1306     if ( !pLock )
1307     {
1308         throw DAVException( DAVException::DAV_NOT_LOCKED );
1309     }
1310 
1311     Init( rEnv );
1312 
1313     boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) );
1314     apr_status_t status = APR_SUCCESS;
1315 
1316     ucb::Lock inLock = pLock->getLock();
1317     //remove lock from lockstore
1318     // so, if something goes wrong, we don't refresh it anymore
1319     m_aSerfLockStore.removeLock(pLock);
1320     delete pLock;
1321 
1322     // remove existing lock
1323     aReqProc->processUnlock( inPath, inLock, status);
1324 
1325     //HandleError will handle the error and throw an exception, if needed
1326     HandleError( aReqProc );
1327 }
1328 
1329 // -------------------------------------------------------------------
1330 // UNLOCK (called from SerfLockStore)
1331 // -------------------------------------------------------------------
1332 bool SerfSession::UNLOCK( SerfLock * pLock )
1333 {
1334     osl::Guard< osl::Mutex > theGuard( m_aMutex );
1335     rtl::OUString inPath = pLock->getResourcePath();
1336 
1337     boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) );
1338     apr_status_t status = APR_SUCCESS;
1339 
1340     rtl::OUString   aToken;
1341     aToken = pLock->getLock().LockTokens[0];
1342 
1343     aReqProc->processUnlock( inPath, pLock->getLock(), status);
1344 
1345     //HandleError will handle the error and throw an exception, if needed
1346     HandleError( aReqProc );
1347 
1348     return true;
1349 }
1350 
1351 // -------------------------------------------------------------------
1352 void SerfSession::abort()
1353     throw ( DAVException )
1354 {
1355     // 11.11.09 (tkr): The following code lines causing crashes if
1356     // closing a ongoing connection. It turned out that this existing
1357     // solution doesn't work in multi-threading environments.
1358     // So I disabled them in 3.2. . Issue #73893# should fix it in OOo 3.3.
1359     //if ( m_pHttpSession )
1360     //    ne_close_connection( m_pHttpSession );
1361 }
1362 
1363 // -------------------------------------------------------------------
1364 const ucbhelper::InternetProxyServer & SerfSession::getProxySettings() const
1365 {
1366     if ( m_aUri.GetScheme().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "http" ) ) ||
1367          m_aUri.GetScheme().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "https" ) ) )
1368     {
1369         return m_rProxyDecider.getProxy( m_aUri.GetScheme(),
1370                                          m_aUri.GetHost(),
1371                                          m_aUri.GetPort() );
1372     }
1373     else
1374     {
1375         // TODO: figure out, if this case can occur
1376         return m_rProxyDecider.getProxy( m_aUri.GetScheme(),
1377                                          rtl::OUString() /* not used */,
1378                                          -1 /* not used */ );
1379     }
1380 }
1381 
1382 /*
1383 // -------------------------------------------------------------------
1384 namespace {
1385 
1386 bool containsLocktoken( const uno::Sequence< ucb::Lock > & rLocks,
1387                         const char * token )
1388 {
1389     for ( sal_Int32 n = 0; n < rLocks.getLength(); ++n )
1390     {
1391         const uno::Sequence< rtl::OUString > & rTokens
1392             = rLocks[ n ].LockTokens;
1393         for ( sal_Int32 m = 0; m < rTokens.getLength(); ++m )
1394         {
1395             if ( rTokens[ m ].equalsAscii( token ) )
1396                 return true;
1397         }
1398     }
1399     return false;
1400 }
1401 
1402 } // namespace
1403 */
1404 
1405 // -------------------------------------------------------------------
1406 // This method doesn't seem to be used.
1407 // In any case the default behavior is to ask a lock whith a life of 3 minutes
1408 // it will then be refreshed automatically (see SerfLockStore class)
1409 // In case of AOO crash the lock will expire by itself
1410 bool SerfSession::removeExpiredLocktoken( const rtl::OUString & /*inURL*/,
1411                                           const DAVRequestEnvironment & /*rEnv*/ )
1412 {
1413     return true;
1414     /*
1415     SerfLock * theLock = m_aSerfLockStore.findByUri( inURL );
1416     if ( !theLock )
1417         return false;
1418 
1419     // do a lockdiscovery to check whether this lock is still valid.
1420     try
1421     {
1422         // @@@ Alternative: use ne_lock_discover() => less overhead
1423 
1424         std::vector< DAVResource > aResources;
1425         std::vector< rtl::OUString > aPropNames;
1426         aPropNames.push_back( DAVProperties::LOCKDISCOVERY );
1427 
1428         PROPFIND( rEnv.m_aRequestURI, DAVZERO, aPropNames, aResources, rEnv );
1429 
1430         if ( aResources.size() == 0 )
1431             return false;
1432 
1433         std::vector< DAVPropertyValue >::const_iterator it
1434             = aResources[ 0 ].properties.begin();
1435         std::vector< DAVPropertyValue >::const_iterator end
1436             = aResources[ 0 ].properties.end();
1437 
1438         while ( it != end )
1439         {
1440             if ( (*it).Name.equals( DAVProperties::LOCKDISCOVERY ) )
1441             {
1442                 uno::Sequence< ucb::Lock > aLocks;
1443                 if ( !( (*it).Value >>= aLocks ) )
1444                     return false;
1445 
1446                 if ( !containsLocktoken( aLocks, theLock->token ) )
1447                 {
1448                     // expired!
1449                     break;
1450                 }
1451 
1452                 // still valid.
1453                 return false;
1454             }
1455             ++it;
1456         }
1457 
1458         // No lockdiscovery prop in propfind result / locktoken not found
1459         // in propfind result -> not locked
1460         OSL_TRACE( "SerfSession::removeExpiredLocktoken: Removing "
1461                    " expired lock token for %s. token: %s",
1462                    rtl::OUStringToOString( inURL,
1463                                            RTL_TEXTENCODING_UTF8 ).getStr(),
1464                    theLock->token );
1465 
1466         m_aSerfLockStore.removeLock( theLock );
1467         ne_lock_destroy( theLock );
1468         return true;
1469     }
1470     catch ( DAVException const & )
1471     {
1472     }
1473     return false;
1474     */
1475 }
1476 
1477 // -------------------------------------------------------------------
1478 // HandleError
1479 // Common Error Handler
1480 // -------------------------------------------------------------------
1481 void SerfSession::HandleError( boost::shared_ptr<SerfRequestProcessor> rReqProc )
1482     throw ( DAVException )
1483 {
1484     m_aEnv = DAVRequestEnvironment();
1485 
1486     if ( rReqProc->mpDAVException )
1487     {
1488         DAVException* mpDAVExp( rReqProc->mpDAVException );
1489 
1490         serf_connection_reset( getSerfConnection() );
1491 
1492         if ( mpDAVExp->getStatus() == 413 &&
1493              m_bNoOfTransferEncodingSwitches < 2 )
1494         {
1495             m_bUseChunkedEncoding = !m_bUseChunkedEncoding;
1496             ++m_bNoOfTransferEncodingSwitches;
1497         }
1498 
1499         throw DAVException( mpDAVExp->getError(),
1500                             mpDAVExp->getData(),
1501                             mpDAVExp->getStatus() );
1502     }
1503 
1504     /*
1505     // Map error code to DAVException.
1506     switch ( nError )
1507     {
1508         case NE_OK:
1509             return;
1510 
1511         case NE_ERROR:        // Generic error
1512         {
1513             rtl::OUString aText = rtl::OUString::createFromAscii(
1514                 ne_get_error( m_pHttpSession ) );
1515 
1516             sal_uInt16 code = makeStatusCode( aText );
1517 
1518             if ( code == SC_LOCKED )
1519             {
1520                 if ( m_aSerfLockStore.findByUri(
1521                          makeAbsoluteURL( inPath ) ) == 0 )
1522                 {
1523                     // locked by 3rd party
1524                     throw DAVException( DAVException::DAV_LOCKED );
1525                 }
1526                 else
1527                 {
1528                     // locked by ourself
1529                     throw DAVException( DAVException::DAV_LOCKED_SELF );
1530                 }
1531             }
1532 
1533             // Special handling for 400 and 412 status codes, which may indicate
1534             // that a lock previously obtained by us has been released meanwhile
1535             // by the server. Unfortunately, RFC is not clear at this point,
1536             // thus server implementations behave different...
1537             else if ( code == SC_BAD_REQUEST || code == SC_PRECONDITION_FAILED )
1538             {
1539                 if ( removeExpiredLocktoken( makeAbsoluteURL( inPath ), rEnv ) )
1540                     throw DAVException( DAVException::DAV_LOCK_EXPIRED );
1541             }
1542 
1543             throw DAVException( DAVException::DAV_HTTP_ERROR, aText, code );
1544         }
1545         case NE_LOOKUP:       // Name lookup failed.
1546             throw DAVException( DAVException::DAV_HTTP_LOOKUP,
1547                                 SerfUri::makeConnectionEndPointString(
1548                                     m_aHostName, m_nPort ) );
1549 
1550         case NE_AUTH:         // User authentication failed on server
1551             throw DAVException( DAVException::DAV_HTTP_AUTH,
1552                                 SerfUri::makeConnectionEndPointString(
1553                                     m_aHostName, m_nPort ) );
1554 
1555         case NE_PROXYAUTH:    // User authentication failed on proxy
1556             throw DAVException( DAVException::DAV_HTTP_AUTHPROXY,
1557                                 SerfUri::makeConnectionEndPointString(
1558                                     m_aProxyName, m_nProxyPort ) );
1559 
1560         case NE_CONNECT:      // Could not connect to server
1561             throw DAVException( DAVException::DAV_HTTP_CONNECT,
1562                                 SerfUri::makeConnectionEndPointString(
1563                                     m_aHostName, m_nPort ) );
1564 
1565         case NE_TIMEOUT:      // Connection timed out
1566             throw DAVException( DAVException::DAV_HTTP_TIMEOUT,
1567                                 SerfUri::makeConnectionEndPointString(
1568                                     m_aHostName, m_nPort ) );
1569 
1570         case NE_FAILED:       // The precondition failed
1571             throw DAVException( DAVException::DAV_HTTP_FAILED,
1572                                 SerfUri::makeConnectionEndPointString(
1573                                     m_aHostName, m_nPort ) );
1574 
1575         case NE_RETRY:        // Retry request (ne_end_request ONLY)
1576             throw DAVException( DAVException::DAV_HTTP_RETRY,
1577                                 SerfUri::makeConnectionEndPointString(
1578                                     m_aHostName, m_nPort ) );
1579 
1580         case NE_REDIRECT:
1581         {
1582             SerfUri aUri( ne_redirect_location( m_pHttpSession ) );
1583             throw DAVException(
1584                 DAVException::DAV_HTTP_REDIRECT, aUri.GetURI() );
1585         }
1586         default:
1587         {
1588             OSL_TRACE( "SerfSession::HandleError : Unknown Serf error code!" );
1589             throw DAVException( DAVException::DAV_HTTP_ERROR,
1590                                 rtl::OUString::createFromAscii(
1591                                     ne_get_error( m_pHttpSession ) ) );
1592         }
1593     }
1594     */
1595 }
1596 
1597 // -------------------------------------------------------------------
1598 // static
1599 bool
1600 SerfSession::getDataFromInputStream(
1601     const uno::Reference< io::XInputStream > & xStream,
1602     uno::Sequence< sal_Int8 > & rData,
1603     bool bAppendTrailingZeroByte )
1604 {
1605     if ( xStream.is() )
1606     {
1607         uno::Reference< io::XSeekable > xSeekable( xStream, uno::UNO_QUERY );
1608         if ( xSeekable.is() )
1609         {
1610             try
1611             {
1612                 sal_Int32 nSize
1613                     = sal::static_int_cast<sal_Int32>(xSeekable->getLength());
1614                 sal_Int32 nRead
1615                     = xStream->readBytes( rData, nSize );
1616 
1617                 if ( nRead == nSize )
1618                 {
1619                     if ( bAppendTrailingZeroByte )
1620                     {
1621                         rData.realloc( nSize + 1 );
1622                         rData[ nSize ] = sal_Int8( 0 );
1623                     }
1624                     return true;
1625                 }
1626             }
1627             catch ( io::NotConnectedException const & )
1628             {
1629                 // readBytes
1630             }
1631             catch ( io::BufferSizeExceededException const & )
1632             {
1633                 // readBytes
1634             }
1635             catch ( io::IOException const & )
1636             {
1637                 // getLength, readBytes
1638             }
1639         }
1640         else
1641         {
1642             try
1643             {
1644                 uno::Sequence< sal_Int8 > aBuffer;
1645                 sal_Int32 nPos = 0;
1646 
1647                 sal_Int32 nRead = xStream->readSomeBytes( aBuffer, 65536 );
1648                 while ( nRead > 0 )
1649                 {
1650                     if ( rData.getLength() < ( nPos + nRead ) )
1651                         rData.realloc( nPos + nRead );
1652 
1653                     aBuffer.realloc( nRead );
1654                     rtl_copyMemory( (void*)( rData.getArray() + nPos ),
1655                                     (const void*)aBuffer.getConstArray(),
1656                                     nRead );
1657                     nPos += nRead;
1658 
1659                     aBuffer.realloc( 0 );
1660                     nRead = xStream->readSomeBytes( aBuffer, 65536 );
1661                 }
1662 
1663                 if ( bAppendTrailingZeroByte )
1664                 {
1665                     rData.realloc( nPos + 1 );
1666                     rData[ nPos ] = sal_Int8( 0 );
1667                 }
1668                 return true;
1669             }
1670             catch ( io::NotConnectedException const & )
1671             {
1672                 // readBytes
1673             }
1674             catch ( io::BufferSizeExceededException const & )
1675             {
1676                 // readBytes
1677             }
1678             catch ( io::IOException const & )
1679             {
1680                 // readBytes
1681             }
1682         }
1683     }
1684     return false;
1685 }
1686 
1687 // ---------------------------------------------------------------------
1688 sal_Bool
1689 SerfSession::isDomainMatch( rtl::OUString certHostName )
1690 {
1691     rtl::OUString hostName = getHostName();
1692 
1693     if (hostName.equalsIgnoreAsciiCase( certHostName ) )
1694         return sal_True;
1695 
1696     if ( 0 == certHostName.indexOf( rtl::OUString::createFromAscii( "*" ) ) &&
1697          hostName.getLength() >= certHostName.getLength()  )
1698     {
1699         rtl::OUString cmpStr = certHostName.copy( 1 );
1700 
1701         if ( hostName.matchIgnoreAsciiCase(
1702                 cmpStr, hostName.getLength() -  cmpStr.getLength() ) )
1703             return sal_True;
1704     }
1705     return sal_False;
1706 }
1707