1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
23 #include <rtl/string.h>
24 #include "comphelper/processfactory.hxx"
25 #include "comphelper/sequence.hxx"
26 #include "ucbhelper/simplecertificatevalidationrequest.hxx"
29 #include <apr_strings.h>
31 #include "DAVAuthListener.hxx"
32 #include <SerfTypes.hxx>
33 #include <SerfSession.hxx>
34 #include <SerfUri.hxx>
35 #include <SerfRequestProcessor.hxx>
36 #include <SerfCallbacks.hxx>
37 #include <SerfInputStream.hxx>
38 #include <UCBDeadPropertyValue.hxx>
40 #include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
41 #include <com/sun/star/security/XCertificate.hpp>
42 #include <com/sun/star/security/CertificateValidity.hpp>
43 #include <com/sun/star/security/CertificateContainerStatus.hpp>
44 #include <com/sun/star/security/CertificateContainer.hpp>
45 #include <com/sun/star/security/XCertificateContainer.hpp>
46 #include <com/sun/star/ucb/Lock.hpp>
47 #include <com/sun/star/xml/crypto/XSEInitializer.hpp>
49 using namespace com::sun::star
;
50 using namespace http_dav_ucp
;
53 // -------------------------------------------------------------------
55 //SerfLockStore SerfSession::m_aSerfLockStore;
57 // -------------------------------------------------------------------
59 // -------------------------------------------------------------------
60 SerfSession::SerfSession(
61 const rtl::Reference
< DAVSessionFactory
> & rSessionFactory
,
62 const OUString
& inUri
,
63 const ucbhelper::InternetProxyDecider
& rProxyDecider
)
64 throw ( DAVException
)
65 : DAVSession( rSessionFactory
)
70 , m_pSerfConnection( 0 )
72 , m_bIsHeadRequestInProgress( false )
73 , m_bUseChunkedEncoding( false )
74 , m_bNoOfTransferEncodingSwitches( 0 )
75 , m_rProxyDecider( rProxyDecider
)
78 m_pSerfContext
= serf_context_create( getAprPool() );
80 m_pSerfBucket_Alloc
= serf_bucket_allocator_create( getAprPool(), NULL
, NULL
);
83 // -------------------------------------------------------------------
85 // -------------------------------------------------------------------
86 SerfSession::~SerfSession( )
88 if ( m_pSerfConnection
)
90 serf_connection_close( m_pSerfConnection
);
91 m_pSerfConnection
= 0;
95 // -------------------------------------------------------------------
96 void SerfSession::Init( const DAVRequestEnvironment
& rEnv
)
97 throw ( DAVException
)
99 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
104 // -------------------------------------------------------------------
105 void SerfSession::Init()
106 throw ( DAVException
)
108 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
110 bool bCreateNewSession
= false;
112 if ( m_pSerfConnection
== 0 )
114 const ucbhelper::InternetProxyServer
& rProxyCfg
= getProxySettings();
116 m_aProxyName
= rProxyCfg
.aName
;
117 m_nProxyPort
= rProxyCfg
.nPort
;
119 // Not yet initialized. Create new session.
120 bCreateNewSession
= true;
124 const ucbhelper::InternetProxyServer
& rProxyCfg
= getProxySettings();
126 if ( ( rProxyCfg
.aName
!= m_aProxyName
)
127 || ( rProxyCfg
.nPort
!= m_nProxyPort
) )
129 m_aProxyName
= rProxyCfg
.aName
;
130 m_nProxyPort
= rProxyCfg
.nPort
;
132 // new session needed, destroy old first
133 serf_connection_close( m_pSerfConnection
);
134 m_pSerfConnection
= 0;
135 bCreateNewSession
= true;
139 if ( bCreateNewSession
)
141 // TODO - close_connection callback
142 apr_status_t status
= serf_connection_create2( &m_pSerfConnection
,
144 *(m_aUri
.getAprUri()),
145 Serf_ConnectSetup
, this,
146 0 /* close connection callback */, 0 /* close connection baton */,
149 if ( m_pSerfConnection
== 0 ||status
!= APR_SUCCESS
)
151 throw DAVException( DAVException::DAV_SESSION_CREATE
,
152 SerfUri::makeConnectionEndPointString( m_aUri
.GetHost(), m_aUri
.GetPort() ) );
155 // Register the session with the lock store
156 // m_aSerfLockStore.registerSession( m_pSerfConnection );
158 if ( m_aProxyName
.getLength() )
160 apr_sockaddr_t
*proxy_address
= NULL
;
161 const apr_status_t status
= apr_sockaddr_info_get( &proxy_address
,
162 OUStringToOString( m_aProxyName
, RTL_TEXTENCODING_UTF8
),
164 static_cast<apr_port_t
>(m_nProxyPort
),
167 if ( status
!= APR_SUCCESS
)
169 throw DAVException( DAVException::DAV_SESSION_CREATE
,
170 SerfUri::makeConnectionEndPointString( m_aUri
.GetHost(), m_aUri
.GetPort() ) );
173 serf_config_proxy( m_pSerfContext
, proxy_address
);
177 serf_config_credentials_callback( m_pSerfContext
, Serf_Credentials
);
179 m_bUseChunkedEncoding
= isSSLNeeded();
183 apr_pool_t
* SerfSession::getAprPool()
185 return apr_environment::AprEnv::getAprEnv()->getAprPool();
188 serf_bucket_alloc_t
* SerfSession::getSerfBktAlloc()
190 return m_pSerfBucket_Alloc
;
193 serf_context_t
* SerfSession::getSerfContext()
195 return m_pSerfContext
;
198 SerfConnection
* SerfSession::getSerfConnection()
200 return m_pSerfConnection
;
203 bool SerfSession::isHeadRequestInProgress()
205 return m_bIsHeadRequestInProgress
;
208 bool SerfSession::isSSLNeeded()
210 return m_aUri
.GetScheme().equalsIgnoreAsciiCase( OUString( "https" ) );
213 char* SerfSession::getHostinfo()
215 return m_aUri
.getAprUri()->hostinfo
;
219 // -------------------------------------------------------------------
221 sal_Bool
SerfSession::CanUse( const OUString
& inUri
)
225 SerfUri
theUri( inUri
);
226 if ( ( theUri
.GetPort() == m_aUri
.GetPort() ) &&
227 ( theUri
.GetHost() == m_aUri
.GetHost() ) &&
228 ( theUri
.GetScheme() == m_aUri
.GetScheme() ) )
233 catch ( DAVException
const & )
240 // -------------------------------------------------------------------
242 sal_Bool
SerfSession::UsesProxy()
245 return ( m_aProxyName
.getLength() > 0 );
248 apr_status_t
SerfSession::setupSerfConnection( apr_socket_t
* inAprSocket
,
249 serf_bucket_t
**outSerfInputBucket
,
250 serf_bucket_t
**outSerfOutputBucket
,
251 apr_pool_t
* /*inAprPool*/ )
253 serf_bucket_t
*tmpInputBkt
;
254 tmpInputBkt
= serf_context_bucket_socket_create( getSerfContext(),
260 tmpInputBkt
= serf_bucket_ssl_decrypt_create( tmpInputBkt
,
263 /** Set the callback that is called to authenticate the
266 serf_ssl_server_cert_chain_callback_set(
267 serf_bucket_ssl_decrypt_context_get(tmpInputBkt
),
268 Serf_CertificateChainValidation
,
270 serf_ssl_set_hostname( serf_bucket_ssl_decrypt_context_get( tmpInputBkt
),
273 *outSerfOutputBucket
= serf_bucket_ssl_encrypt_create( *outSerfOutputBucket
,
274 serf_bucket_ssl_decrypt_context_get( tmpInputBkt
),
278 *outSerfInputBucket
= tmpInputBkt
;
283 apr_status_t
SerfSession::provideSerfCredentials( bool bGiveProvidedCredentialsASecondTry
,
286 serf_request_t
* /*inRequest*/,
288 const char *inAuthProtocol
,
290 apr_pool_t
*inAprPool
)
292 DAVAuthListener
* pListener
= getRequestEnvironment().m_xAuthListener
.get();
296 return SERF_ERROR_AUTHN_FAILED
;
299 OUString theUserName
;
300 OUString thePassWord
;
303 SerfUri
uri( getRequestEnvironment().m_aRequestURI
);
304 OUString
aUserInfo( uri
.GetUserInfo() );
305 if ( aUserInfo
.getLength() )
307 sal_Int32 nPos
= aUserInfo
.indexOf( '@' );
310 theUserName
= aUserInfo
;
314 theUserName
= aUserInfo
.copy( 0, nPos
);
315 thePassWord
= aUserInfo
.copy( nPos
+ 1 );
319 catch ( DAVException
const & )
322 return SERF_ERROR_AUTHN_FAILED
;
325 const bool bCanUseSystemCreds
= ( ( strcasecmp( inAuthProtocol
, "NTLM" ) == 0 ) ||
326 ( strcasecmp( inAuthProtocol
, "Negotiate" ) == 0 ) );
328 int theRetVal
= pListener
->authenticate( OUString::createFromAscii( inRealm
),
333 bGiveProvidedCredentialsASecondTry
? sal_False
: sal_True
);
335 if ( theRetVal
== 0 )
337 *outUsername
= apr_pstrdup( inAprPool
, OUStringToOString( theUserName
, RTL_TEXTENCODING_UTF8
) );
338 *outPassword
= apr_pstrdup( inAprPool
, OUStringToOString( thePassWord
, RTL_TEXTENCODING_UTF8
) );
341 return theRetVal
!= 0 ? SERF_ERROR_AUTHN_FAILED
: APR_SUCCESS
;
345 // -------------------------------------------------------------------
347 OUString
GetHostnamePart( const OUString
& _rRawString
)
350 OUString sPartId
= OUString::createFromAscii( "CN=" );
351 sal_Int32 nContStart
= _rRawString
.indexOf( sPartId
);
352 if ( nContStart
!= -1 )
354 nContStart
= nContStart
+ sPartId
.getLength();
356 = _rRawString
.indexOf( sal_Unicode( ',' ), nContStart
);
357 sPart
= _rRawString
.copy( nContStart
, nContEnd
- nContStart
);
364 apr_status_t
SerfSession::verifySerfCertificateChain (
366 const char** pCertificateChainBase64Encoded
,
367 int nCertificateChainLength
)
370 if (pCertificateChainBase64Encoded
== NULL
|| nCertificateChainLength
<=0)
372 OSL_ASSERT(pCertificateChainBase64Encoded
!= NULL
);
373 OSL_ASSERT(nCertificateChainLength
>0);
374 return SERF_SSL_CERT_UNKNOWN_FAILURE
;
377 // Create some crypto objects to decode and handle the base64
378 // encoded certificate chain.
379 uno::Reference
< xml::crypto::XSEInitializer
> xSEInitializer
;
380 uno::Reference
< security::XCertificateContainer
> xCertificateContainer
;
381 uno::Reference
< xml::crypto::XXMLSecurityContext
> xSecurityContext
;
382 uno::Reference
< xml::crypto::XSecurityEnvironment
> xSecurityEnv
;
385 // Create a certificate container.
386 xCertificateContainer
= security::CertificateContainer::create( comphelper::getComponentContext(getMSF()) );
388 xSEInitializer
= uno::Reference
< xml::crypto::XSEInitializer
>(
389 getMSF()->createInstance(
390 OUString::createFromAscii( "com.sun.star.xml.crypto.SEInitializer" ) ),
391 uno::UNO_QUERY_THROW
);
393 xSecurityContext
= xSEInitializer
->createSecurityContext( OUString() );
394 if (xSecurityContext
.is())
395 xSecurityEnv
= xSecurityContext
->getSecurityEnvironment();
397 if ( ! xSecurityContext
.is() || ! xSecurityEnv
.is())
399 // Do we have to dispose xSEInitializer or xCertificateContainer?
400 return SERF_SSL_CERT_UNKNOWN_FAILURE
;
403 catch ( uno::Exception
const &)
405 return SERF_SSL_CERT_UNKNOWN_FAILURE
;
408 // Decode the server certificate.
409 uno::Reference
< security::XCertificate
> xServerCertificate(
410 xSecurityEnv
->createCertificateFromAscii(
411 OUString::createFromAscii(pCertificateChainBase64Encoded
[0])));
412 if ( ! xServerCertificate
.is())
413 return SERF_SSL_CERT_UNKNOWN_FAILURE
;
415 // Get the subject from the server certificate.
416 OUString
sServerCertificateSubject (xServerCertificate
->getSubjectName());
417 sal_Int32 nIndex
= 0;
420 const OUString
sToken (sServerCertificateSubject
.getToken(0, ',', nIndex
));
421 if (sToken
.startsWith("CN="))
423 sServerCertificateSubject
= sToken
.copy(3);
426 else if (sToken
.startsWith(" CN="))
428 sServerCertificateSubject
= sToken
.copy(4);
433 // When the certificate container already contains a (trusted)
434 // entry for the server then we do not have to authenticate any
436 const security::CertificateContainerStatus
eStatus (
437 xCertificateContainer
->hasCertificate(
438 getHostName(), sServerCertificateSubject
) );
439 if (eStatus
!= security::CertificateContainerStatus_NOCERT
)
441 return eStatus
== security::CertificateContainerStatus_TRUSTED
443 : SERF_SSL_CERT_UNKNOWN_FAILURE
;
446 // The shortcut failed, so try to verify the whole chain. This is
447 // done outside the isDomainMatch() block because the result is
448 // used by the interaction handler.
449 std::vector
< uno::Reference
< security::XCertificate
> > aChain
;
450 for (int nIndex
=1; nIndex
<nCertificateChainLength
; ++nIndex
)
452 uno::Reference
< security::XCertificate
> xCertificate(
453 xSecurityEnv
->createCertificateFromAscii(
454 OUString::createFromAscii(pCertificateChainBase64Encoded
[nIndex
])));
455 if ( ! xCertificate
.is())
456 return SERF_SSL_CERT_UNKNOWN_FAILURE
;
457 aChain
.push_back(xCertificate
);
459 const sal_Int64
nVerificationResult (xSecurityEnv
->verifyCertificate(
461 ::comphelper::containerToSequence(aChain
)));
463 // When the certificate matches the host name then we can use the
464 // result of the verification.
465 if (isDomainMatch(sServerCertificateSubject
))
468 if (nVerificationResult
== 0)
470 // Certificate (chain) is valid.
471 xCertificateContainer
->addCertificate(getHostName(), sServerCertificateSubject
, sal_True
);
474 else if ((nVerificationResult
& security::CertificateValidity::CHAIN_INCOMPLETE
) != 0)
476 // We do not have enough information for verification,
477 // neither automatically (as we just discovered) nor
478 // manually (so there is no point in showing any dialog.)
479 return SERF_SSL_CERT_UNKNOWN_FAILURE
;
481 else if ((nVerificationResult
&
482 (security::CertificateValidity::INVALID
| security::CertificateValidity::REVOKED
)) != 0)
484 // Certificate (chain) is invalid.
485 xCertificateContainer
->addCertificate(getHostName(), sServerCertificateSubject
, sal_False
);
486 return SERF_SSL_CERT_UNKNOWN_FAILURE
;
490 // For all other we have to ask the user.
494 // We have not been able to automatically verify (or falsify) the
495 // certificate chain. To resolve this we have to ask the user.
496 const uno::Reference
< ucb::XCommandEnvironment
> xEnv( getRequestEnvironment().m_xEnv
);
499 uno::Reference
< task::XInteractionHandler
> xIH( xEnv
->getInteractionHandler() );
502 rtl::Reference
< ucbhelper::SimpleCertificateValidationRequest
>
503 xRequest( new ucbhelper::SimpleCertificateValidationRequest(
504 static_cast<sal_Int32
>(nVerificationResult
), xServerCertificate
, getHostName() ) );
505 xIH
->handle( xRequest
.get() );
507 rtl::Reference
< ucbhelper::InteractionContinuation
> xSelection
508 = xRequest
->getSelection();
510 if ( xSelection
.is() )
512 uno::Reference
< task::XInteractionApprove
> xApprove(
513 xSelection
.get(), uno::UNO_QUERY
);
516 xCertificateContainer
->addCertificate( getHostName(), sServerCertificateSubject
, sal_True
);
522 xCertificateContainer
->addCertificate( getHostName(), sServerCertificateSubject
, sal_False
);
523 return SERF_SSL_CERT_UNKNOWN_FAILURE
;
530 xCertificateContainer
->addCertificate( getHostName(), sServerCertificateSubject
, sal_False
);
531 return SERF_SSL_CERT_UNKNOWN_FAILURE
;
535 return SERF_SSL_CERT_UNKNOWN_FAILURE
;
538 serf_bucket_t
* SerfSession::acceptSerfResponse( serf_request_t
* inSerfRequest
,
539 serf_bucket_t
* inSerfStreamBucket
,
540 apr_pool_t
* /*inAprPool*/ )
542 // get the per-request bucket allocator
543 serf_bucket_alloc_t
* SerfBktAlloc
= serf_request_get_alloc( inSerfRequest
);
545 // create a barrier bucket so the response doesn't eat us!
546 serf_bucket_t
*responseBkt
= serf_bucket_barrier_create( inSerfStreamBucket
,
549 // create response bucket
550 responseBkt
= serf_bucket_response_create( responseBkt
,
553 if ( isHeadRequestInProgress() )
555 // advise the response bucket that this was from a HEAD request and that it should not expect to see a response body.
556 serf_bucket_response_set_head( responseBkt
);
562 SerfRequestProcessor
* SerfSession::createReqProc( const OUString
& inPath
)
564 return new SerfRequestProcessor( *this,
566 m_bUseChunkedEncoding
);
569 // -------------------------------------------------------------------
570 // PROPFIND - allprop & named
571 // -------------------------------------------------------------------
572 void SerfSession::PROPFIND( const OUString
& inPath
,
574 const std::vector
< OUString
> & inPropNames
,
575 std::vector
< DAVResource
> & ioResources
,
576 const DAVRequestEnvironment
& rEnv
)
577 throw ( DAVException
)
579 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
583 apr_status_t status
= APR_SUCCESS
;
584 boost::shared_ptr
<SerfRequestProcessor
> aReqProc( createReqProc( inPath
) );
585 aReqProc
->processPropFind( inDepth
,
590 if ( status
== APR_SUCCESS
&&
591 aReqProc
->mpDAVException
== 0 &&
592 ioResources
.empty() )
594 m_aEnv
= DAVRequestEnvironment();
595 throw DAVException( DAVException::DAV_HTTP_ERROR
, inPath
, (sal_uInt16
)APR_EGENERAL
);
597 HandleError( aReqProc
);
600 // -------------------------------------------------------------------
601 // PROPFIND - propnames
602 // -------------------------------------------------------------------
603 void SerfSession::PROPFIND( const OUString
& inPath
,
605 std::vector
< DAVResourceInfo
> & ioResInfo
,
606 const DAVRequestEnvironment
& rEnv
)
607 throw( DAVException
)
609 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
613 apr_status_t status
= APR_SUCCESS
;
614 boost::shared_ptr
<SerfRequestProcessor
> aReqProc( createReqProc( inPath
) );
615 aReqProc
->processPropFind( inDepth
,
619 if ( status
== APR_SUCCESS
&&
620 aReqProc
->mpDAVException
== 0 &&
623 m_aEnv
= DAVRequestEnvironment();
624 throw DAVException( DAVException::DAV_HTTP_ERROR
, inPath
, (sal_uInt16
)APR_EGENERAL
);
626 HandleError( aReqProc
);
629 // -------------------------------------------------------------------
631 // -------------------------------------------------------------------
632 void SerfSession::PROPPATCH( const OUString
& inPath
,
633 const std::vector
< ProppatchValue
> & inValues
,
634 const DAVRequestEnvironment
& rEnv
)
635 throw( DAVException
)
637 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
641 apr_status_t status
= APR_SUCCESS
;
642 boost::shared_ptr
<SerfRequestProcessor
> aReqProc( createReqProc( inPath
) );
643 aReqProc
->processPropPatch( inValues
,
646 HandleError( aReqProc
);
649 // -------------------------------------------------------------------
651 // -------------------------------------------------------------------
652 void SerfSession::HEAD( const OUString
& inPath
,
653 const std::vector
< OUString
> & inHeaderNames
,
654 DAVResource
& ioResource
,
655 const DAVRequestEnvironment
& rEnv
)
656 throw( DAVException
)
658 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
662 m_bIsHeadRequestInProgress
= true;
664 boost::shared_ptr
<SerfRequestProcessor
> aReqProc( createReqProc( inPath
) );
665 ioResource
.uri
= inPath
;
666 ioResource
.properties
.clear();
667 apr_status_t status
= APR_SUCCESS
;
668 aReqProc
->processHead( inHeaderNames
,
672 m_bIsHeadRequestInProgress
= false;
674 HandleError( aReqProc
);
677 // -------------------------------------------------------------------
679 // -------------------------------------------------------------------
680 uno::Reference
< io::XInputStream
>
681 SerfSession::GET( const OUString
& inPath
,
682 const DAVRequestEnvironment
& rEnv
)
683 throw ( DAVException
)
685 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
689 uno::Reference
< SerfInputStream
> xInputStream( new SerfInputStream
);
690 apr_status_t status
= APR_SUCCESS
;
691 boost::shared_ptr
<SerfRequestProcessor
> aReqProc( createReqProc( inPath
) );
692 aReqProc
->processGet( xInputStream
,
695 HandleError( aReqProc
);
697 return uno::Reference
< io::XInputStream
>( xInputStream
.get() );
700 // -------------------------------------------------------------------
702 // -------------------------------------------------------------------
703 void SerfSession::GET( const OUString
& inPath
,
704 uno::Reference
< io::XOutputStream
> & ioOutputStream
,
705 const DAVRequestEnvironment
& rEnv
)
706 throw ( DAVException
)
708 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
712 apr_status_t status
= APR_SUCCESS
;
713 boost::shared_ptr
<SerfRequestProcessor
> aReqProc( createReqProc( inPath
) );
714 aReqProc
->processGet( ioOutputStream
,
717 HandleError( aReqProc
);
720 // -------------------------------------------------------------------
722 // -------------------------------------------------------------------
723 uno::Reference
< io::XInputStream
>
724 SerfSession::GET( const OUString
& inPath
,
725 const std::vector
< OUString
> & inHeaderNames
,
726 DAVResource
& ioResource
,
727 const DAVRequestEnvironment
& rEnv
)
728 throw ( DAVException
)
730 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
734 boost::shared_ptr
<SerfRequestProcessor
> aReqProc( createReqProc( inPath
) );
735 uno::Reference
< SerfInputStream
> xInputStream( new SerfInputStream
);
736 ioResource
.uri
= inPath
;
737 ioResource
.properties
.clear();
738 apr_status_t status
= APR_SUCCESS
;
739 aReqProc
->processGet( xInputStream
,
744 HandleError( aReqProc
);
746 return uno::Reference
< io::XInputStream
>( xInputStream
.get() );
750 // -------------------------------------------------------------------
752 // -------------------------------------------------------------------
753 void SerfSession::GET( const OUString
& inPath
,
754 uno::Reference
< io::XOutputStream
> & ioOutputStream
,
755 const std::vector
< OUString
> & inHeaderNames
,
756 DAVResource
& ioResource
,
757 const DAVRequestEnvironment
& rEnv
)
758 throw ( DAVException
)
760 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
764 boost::shared_ptr
<SerfRequestProcessor
> aReqProc( createReqProc( inPath
) );
765 ioResource
.uri
= inPath
;
766 ioResource
.properties
.clear();
767 apr_status_t status
= APR_SUCCESS
;
768 aReqProc
->processGet( ioOutputStream
,
773 HandleError( aReqProc
);
776 // -------------------------------------------------------------------
778 // -------------------------------------------------------------------
779 void SerfSession::PUT( const OUString
& inPath
,
780 const uno::Reference
< io::XInputStream
> & inInputStream
,
781 const DAVRequestEnvironment
& rEnv
)
782 throw ( DAVException
)
784 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
788 boost::shared_ptr
<SerfRequestProcessor
> aReqProc( createReqProc( inPath
) );
789 uno::Sequence
< sal_Int8
> aDataToSend
;
790 if ( !getDataFromInputStream( inInputStream
, aDataToSend
, false ) )
791 throw DAVException( DAVException::DAV_INVALID_ARG
);
792 apr_status_t status
= APR_SUCCESS
;
793 aReqProc
->processPut( reinterpret_cast< const char * >( aDataToSend
.getConstArray() ),
794 aDataToSend
.getLength(),
797 HandleError( aReqProc
);
800 // -------------------------------------------------------------------
802 // -------------------------------------------------------------------
803 uno::Reference
< io::XInputStream
>
804 SerfSession::POST( const OUString
& inPath
,
805 const OUString
& rContentType
,
806 const OUString
& rReferer
,
807 const uno::Reference
< io::XInputStream
> & inInputStream
,
808 const DAVRequestEnvironment
& rEnv
)
809 throw ( DAVException
)
811 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
813 uno::Sequence
< sal_Int8
> aDataToSend
;
814 if ( !getDataFromInputStream( inInputStream
, aDataToSend
, true ) )
816 throw DAVException( DAVException::DAV_INVALID_ARG
);
821 boost::shared_ptr
<SerfRequestProcessor
> aReqProc( createReqProc( inPath
) );
822 uno::Reference
< SerfInputStream
> xInputStream( new SerfInputStream
);
823 apr_status_t status
= APR_SUCCESS
;
824 aReqProc
->processPost( reinterpret_cast< const char * >( aDataToSend
.getConstArray() ),
825 aDataToSend
.getLength(),
831 HandleError( aReqProc
);
832 return uno::Reference
< io::XInputStream
>( xInputStream
.get() );
835 // -------------------------------------------------------------------
837 // -------------------------------------------------------------------
838 void SerfSession::POST( const OUString
& inPath
,
839 const OUString
& rContentType
,
840 const OUString
& rReferer
,
841 const uno::Reference
< io::XInputStream
> & inInputStream
,
842 uno::Reference
< io::XOutputStream
> & oOutputStream
,
843 const DAVRequestEnvironment
& rEnv
)
844 throw ( DAVException
)
846 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
848 uno::Sequence
< sal_Int8
> aDataToSend
;
849 if ( !getDataFromInputStream( inInputStream
, aDataToSend
, true ) )
851 throw DAVException( DAVException::DAV_INVALID_ARG
);
856 boost::shared_ptr
<SerfRequestProcessor
> aReqProc( createReqProc( inPath
) );
857 apr_status_t status
= APR_SUCCESS
;
858 aReqProc
->processPost( reinterpret_cast< const char * >( aDataToSend
.getConstArray() ),
859 aDataToSend
.getLength(),
865 HandleError( aReqProc
);
868 // -------------------------------------------------------------------
870 // -------------------------------------------------------------------
871 void SerfSession::MKCOL( const OUString
& inPath
,
872 const DAVRequestEnvironment
& rEnv
)
873 throw ( DAVException
)
875 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
879 boost::shared_ptr
<SerfRequestProcessor
> aReqProc( createReqProc( inPath
) );
880 apr_status_t status
= APR_SUCCESS
;
881 aReqProc
->processMkCol( status
);
883 HandleError( aReqProc
);
886 // -------------------------------------------------------------------
888 // -------------------------------------------------------------------
889 void SerfSession::COPY( const OUString
& inSourceURL
,
890 const OUString
& inDestinationURL
,
891 const DAVRequestEnvironment
& rEnv
,
892 sal_Bool inOverWrite
)
893 throw ( DAVException
)
895 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
899 SerfUri
theSourceUri( inSourceURL
);
900 boost::shared_ptr
<SerfRequestProcessor
> aReqProc( createReqProc( theSourceUri
.GetPath() ) );
901 apr_status_t status
= APR_SUCCESS
;
902 aReqProc
->processCopy( inDestinationURL
,
903 (inOverWrite
? true : false),
906 HandleError( aReqProc
);
909 // -------------------------------------------------------------------
911 // -------------------------------------------------------------------
912 void SerfSession::MOVE( const OUString
& inSourceURL
,
913 const OUString
& inDestinationURL
,
914 const DAVRequestEnvironment
& rEnv
,
915 sal_Bool inOverWrite
)
916 throw ( DAVException
)
918 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
922 SerfUri
theSourceUri( inSourceURL
);
923 boost::shared_ptr
<SerfRequestProcessor
> aReqProc( createReqProc( theSourceUri
.GetPath() ) );
924 apr_status_t status
= APR_SUCCESS
;
925 aReqProc
->processMove( inDestinationURL
,
926 (inOverWrite
? true : false),
929 HandleError( aReqProc
);
932 // -------------------------------------------------------------------
934 // -------------------------------------------------------------------
935 void SerfSession::DESTROY( const OUString
& inPath
,
936 const DAVRequestEnvironment
& rEnv
)
937 throw ( DAVException
)
939 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
943 boost::shared_ptr
<SerfRequestProcessor
> aReqProc( createReqProc( inPath
) );
944 apr_status_t status
= APR_SUCCESS
;
945 aReqProc
->processDelete( status
);
947 HandleError( aReqProc
);
950 // -------------------------------------------------------------------
954 sal_Int32 lastChanceToSendRefreshRequest( TimeValue const & rStart,
958 osl_getSystemTime( &aEnd );
960 // Try to estimate a safe absolute time for sending the
961 // lock refresh request.
962 sal_Int32 lastChanceToSendRefreshRequest = -1;
963 if ( timeout != NE_TIMEOUT_INFINITE )
965 sal_Int32 calltime = aEnd.Seconds - rStart.Seconds;
966 if ( calltime <= timeout )
968 lastChanceToSendRefreshRequest
969 = aEnd.Seconds + timeout - calltime;
973 OSL_TRACE( "No chance to refresh lock before timeout!" );
976 return lastChanceToSendRefreshRequest;
981 // -------------------------------------------------------------------
982 // LOCK (set new lock)
983 // -------------------------------------------------------------------
984 void SerfSession::LOCK( const OUString
& inPath
,
985 ucb::Lock
& /*rLock*/,
986 const DAVRequestEnvironment
& rEnv
)
987 throw ( DAVException
)
989 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
993 boost::shared_ptr
<SerfRequestProcessor
> aReqProc( createReqProc( inPath
) );
994 HandleError( aReqProc
);
995 /* Create a depth zero, exclusive write lock, with default timeout
996 * (allowing a server to pick a default). token, owner and uri are
999 SerfLock * theLock = ne_lock_create();
1003 ne_uri_parse( OUStringToOString( makeAbsoluteURL( inPath ),
1004 RTL_TEXTENCODING_UTF8 ).getStr(),
1006 theLock->uri = aUri;
1008 // Set the lock depth
1009 switch( rLock.Depth )
1011 case ucb::LockDepth_ZERO:
1012 theLock->depth = NE_DEPTH_ZERO;
1014 case ucb::LockDepth_ONE:
1015 theLock->depth = NE_DEPTH_ONE;
1017 case ucb::LockDepth_INFINITY:
1018 theLock->depth = NE_DEPTH_INFINITE;
1021 throw DAVException( DAVException::DAV_INVALID_ARG );
1024 // Set the lock scope
1025 switch ( rLock.Scope )
1027 case ucb::LockScope_EXCLUSIVE:
1028 theLock->scope = ne_lockscope_exclusive;
1030 case ucb::LockScope_SHARED:
1031 theLock->scope = ne_lockscope_shared;
1034 throw DAVException( DAVException::DAV_INVALID_ARG );
1037 // Set the lock timeout
1038 theLock->timeout = (long)rLock.Timeout;
1040 // Set the lock owner
1042 rLock.Owner >>= aValue;
1044 ne_strdup( OUStringToOString( aValue,
1045 RTL_TEXTENCODING_UTF8 ).getStr() );
1046 TimeValue startCall;
1047 osl_getSystemTime( &startCall );
1049 int theRetVal = ne_lock( m_pHttpSession, theLock );
1051 if ( theRetVal == NE_OK )
1053 m_aSerfLockStore.addLock( theLock,
1055 lastChanceToSendRefreshRequest(
1056 startCall, theLock->timeout ) );
1058 uno::Sequence< OUString > aTokens( 1 );
1059 aTokens[ 0 ] = OUString::createFromAscii( theLock->token );
1060 rLock.LockTokens = aTokens;
1062 OSL_TRACE( "SerfSession::LOCK: created lock for %s. token: %s",
1063 OUStringToOString( makeAbsoluteURL( inPath ),
1064 RTL_TEXTENCODING_UTF8 ).getStr(),
1069 ne_lock_destroy( theLock );
1071 OSL_TRACE( "SerfSession::LOCK: obtaining lock for %s failed!",
1072 OUStringToOString( makeAbsoluteURL( inPath ),
1073 RTL_TEXTENCODING_UTF8 ).getStr() );
1076 HandleError( theRetVal, inPath, rEnv );
1080 // -------------------------------------------------------------------
1081 // LOCK (refresh existing lock)
1082 // -------------------------------------------------------------------
1083 sal_Int64
SerfSession::LOCK( const OUString
& /*inPath*/,
1085 const DAVRequestEnvironment
& /*rEnv*/ )
1086 throw ( DAVException
)
1088 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1092 // Try to get the neon lock from lock store
1094 = m_aSerfLockStore.findByUri( makeAbsoluteURL( inPath ) );
1096 throw DAVException( DAVException::DAV_NOT_LOCKED );
1100 // refresh existing lock.
1101 theLock->timeout = static_cast< long >( nTimeout );
1103 TimeValue startCall;
1104 osl_getSystemTime( &startCall );
1106 int theRetVal = ne_lock_refresh( m_pHttpSession, theLock );
1108 if ( theRetVal == NE_OK )
1110 m_aSerfLockStore.updateLock( theLock,
1111 lastChanceToSendRefreshRequest(
1112 startCall, theLock->timeout ) );
1115 HandleError( theRetVal, inPath, rEnv );
1117 return theLock->timeout;
1121 // -------------------------------------------------------------------
1122 // LOCK (refresh existing lock)
1123 // -------------------------------------------------------------------
1124 bool SerfSession::LOCK( SerfLock
* /*pLock*/,
1125 sal_Int32
& /*rlastChanceToSendRefreshRequest*/ )
1127 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1131 // refresh existing lock.
1133 TimeValue startCall;
1134 osl_getSystemTime( &startCall );
1136 if ( ne_lock_refresh( m_pHttpSession, pLock ) == NE_OK )
1138 rlastChanceToSendRefreshRequest
1139 = lastChanceToSendRefreshRequest( startCall, pLock->timeout );
1141 OSL_TRACE( "Lock successfully refreshed." );
1146 OSL_TRACE( "Lock not refreshed!" );
1152 // -------------------------------------------------------------------
1154 // -------------------------------------------------------------------
1155 void SerfSession::UNLOCK( const OUString
& /*inPath*/,
1156 const DAVRequestEnvironment
& /*rEnv*/ )
1157 throw ( DAVException
)
1159 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1162 // get the neon lock from lock store
1164 = m_aSerfLockStore.findByUri( makeAbsoluteURL( inPath ) );
1166 throw DAVException( DAVException::DAV_NOT_LOCKED );
1170 int theRetVal = ne_unlock( m_pHttpSession, theLock );
1172 if ( theRetVal == NE_OK )
1174 m_aSerfLockStore.removeLock( theLock );
1175 ne_lock_destroy( theLock );
1179 OSL_TRACE( "SerfSession::UNLOCK: unlocking of %s failed.",
1180 OUStringToOString( makeAbsoluteURL( inPath ),
1181 RTL_TEXTENCODING_UTF8 ).getStr() );
1184 HandleError( theRetVal, inPath, rEnv );
1188 // -------------------------------------------------------------------
1190 // -------------------------------------------------------------------
1191 bool SerfSession::UNLOCK( SerfLock
* /*pLock*/ )
1193 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1197 if ( ne_unlock( m_pHttpSession, pLock ) == NE_OK )
1199 OSL_TRACE( "UNLOCK succeeded." );
1204 OSL_TRACE( "UNLOCK failed!" );
1210 // -------------------------------------------------------------------
1211 void SerfSession::abort()
1212 throw ( DAVException
)
1214 // 11.11.09 (tkr): The following code lines causing crashes if
1215 // closing a ongoing connection. It turned out that this existing
1216 // solution doesn't work in multi-threading environments.
1217 // So I disabled them in 3.2. . Issue #73893# should fix it in OOo 3.3.
1218 //if ( m_pHttpSession )
1219 // ne_close_connection( m_pHttpSession );
1222 // -------------------------------------------------------------------
1223 const ucbhelper::InternetProxyServer
& SerfSession::getProxySettings() const
1225 if ( m_aUri
.GetScheme() == "http" || m_aUri
.GetScheme() == "https" )
1227 return m_rProxyDecider
.getProxy( m_aUri
.GetScheme(),
1233 // TODO: figure out, if this case can occur
1234 return m_rProxyDecider
.getProxy( m_aUri
.GetScheme(),
1235 OUString() /* not used */,
1236 -1 /* not used */ );
1241 // -------------------------------------------------------------------
1244 bool containsLocktoken( const uno::Sequence< ucb::Lock > & rLocks,
1245 const char * token )
1247 for ( sal_Int32 n = 0; n < rLocks.getLength(); ++n )
1249 const uno::Sequence< OUString > & rTokens
1250 = rLocks[ n ].LockTokens;
1251 for ( sal_Int32 m = 0; m < rTokens.getLength(); ++m )
1253 if ( rTokens[ m ].equalsAscii( token ) )
1263 // -------------------------------------------------------------------
1264 bool SerfSession::removeExpiredLocktoken( const OUString
& /*inURL*/,
1265 const DAVRequestEnvironment
& /*rEnv*/ )
1269 SerfLock * theLock = m_aSerfLockStore.findByUri( inURL );
1273 // do a lockdiscovery to check whether this lock is still valid.
1276 // @@@ Alternative: use ne_lock_discover() => less overhead
1278 std::vector< DAVResource > aResources;
1279 std::vector< OUString > aPropNames;
1280 aPropNames.push_back( DAVProperties::LOCKDISCOVERY );
1282 PROPFIND( rEnv.m_aRequestURI, DAVZERO, aPropNames, aResources, rEnv );
1284 if ( aResources.size() == 0 )
1287 std::vector< DAVPropertyValue >::const_iterator it
1288 = aResources[ 0 ].properties.begin();
1289 std::vector< DAVPropertyValue >::const_iterator end
1290 = aResources[ 0 ].properties.end();
1294 if ( (*it).Name.equals( DAVProperties::LOCKDISCOVERY ) )
1296 uno::Sequence< ucb::Lock > aLocks;
1297 if ( !( (*it).Value >>= aLocks ) )
1300 if ( !containsLocktoken( aLocks, theLock->token ) )
1312 // No lockdiscovery prop in propfind result / locktoken not found
1313 // in propfind result -> not locked
1314 OSL_TRACE( "SerfSession::removeExpiredLocktoken: Removing "
1315 " expired lock token for %s. token: %s",
1316 OUStringToOString( inURL,
1317 RTL_TEXTENCODING_UTF8 ).getStr(),
1320 m_aSerfLockStore.removeLock( theLock );
1321 ne_lock_destroy( theLock );
1324 catch ( DAVException const & )
1331 // -------------------------------------------------------------------
1333 // Common Error Handler
1334 // -------------------------------------------------------------------
1335 void SerfSession::HandleError( boost::shared_ptr
<SerfRequestProcessor
> rReqProc
)
1336 throw ( DAVException
)
1338 m_aEnv
= DAVRequestEnvironment();
1340 if ( rReqProc
->mpDAVException
)
1342 DAVException
* mpDAVExp( rReqProc
->mpDAVException
);
1344 serf_connection_reset( getSerfConnection() );
1346 if ( mpDAVExp
->getStatus() == 413 &&
1347 m_bNoOfTransferEncodingSwitches
< 2 )
1349 m_bUseChunkedEncoding
= !m_bUseChunkedEncoding
;
1350 ++m_bNoOfTransferEncodingSwitches
;
1353 throw DAVException( mpDAVExp
->getError(),
1354 mpDAVExp
->getData(),
1355 mpDAVExp
->getStatus() );
1359 // Map error code to DAVException.
1365 case NE_ERROR: // Generic error
1367 OUString aText = OUString::createFromAscii(
1368 ne_get_error( m_pHttpSession ) );
1370 sal_uInt16 code = makeStatusCode( aText );
1372 if ( code == SC_LOCKED )
1374 if ( m_aSerfLockStore.findByUri(
1375 makeAbsoluteURL( inPath ) ) == 0 )
1377 // locked by 3rd party
1378 throw DAVException( DAVException::DAV_LOCKED );
1382 // locked by ourself
1383 throw DAVException( DAVException::DAV_LOCKED_SELF );
1387 // Special handling for 400 and 412 status codes, which may indicate
1388 // that a lock previously obtained by us has been released meanwhile
1389 // by the server. Unfortunately, RFC is not clear at this point,
1390 // thus server implementations behave different...
1391 else if ( code == SC_BAD_REQUEST || code == SC_PRECONDITION_FAILED )
1393 if ( removeExpiredLocktoken( makeAbsoluteURL( inPath ), rEnv ) )
1394 throw DAVException( DAVException::DAV_LOCK_EXPIRED );
1397 throw DAVException( DAVException::DAV_HTTP_ERROR, aText, code );
1399 case NE_LOOKUP: // Name lookup failed.
1400 throw DAVException( DAVException::DAV_HTTP_LOOKUP,
1401 SerfUri::makeConnectionEndPointString(
1402 m_aHostName, m_nPort ) );
1404 case NE_AUTH: // User authentication failed on server
1405 throw DAVException( DAVException::DAV_HTTP_AUTH,
1406 SerfUri::makeConnectionEndPointString(
1407 m_aHostName, m_nPort ) );
1409 case NE_PROXYAUTH: // User authentication failed on proxy
1410 throw DAVException( DAVException::DAV_HTTP_AUTHPROXY,
1411 SerfUri::makeConnectionEndPointString(
1412 m_aProxyName, m_nProxyPort ) );
1414 case NE_CONNECT: // Could not connect to server
1415 throw DAVException( DAVException::DAV_HTTP_CONNECT,
1416 SerfUri::makeConnectionEndPointString(
1417 m_aHostName, m_nPort ) );
1419 case NE_TIMEOUT: // Connection timed out
1420 throw DAVException( DAVException::DAV_HTTP_TIMEOUT,
1421 SerfUri::makeConnectionEndPointString(
1422 m_aHostName, m_nPort ) );
1424 case NE_FAILED: // The precondition failed
1425 throw DAVException( DAVException::DAV_HTTP_FAILED,
1426 SerfUri::makeConnectionEndPointString(
1427 m_aHostName, m_nPort ) );
1429 case NE_RETRY: // Retry request (ne_end_request ONLY)
1430 throw DAVException( DAVException::DAV_HTTP_RETRY,
1431 SerfUri::makeConnectionEndPointString(
1432 m_aHostName, m_nPort ) );
1436 SerfUri aUri( ne_redirect_location( m_pHttpSession ) );
1438 DAVException::DAV_HTTP_REDIRECT, aUri.GetURI() );
1442 OSL_TRACE( "SerfSession::HandleError : Unknown Serf error code!" );
1443 throw DAVException( DAVException::DAV_HTTP_ERROR,
1444 OUString::createFromAscii(
1445 ne_get_error( m_pHttpSession ) ) );
1451 // -------------------------------------------------------------------
1454 SerfSession::getDataFromInputStream(
1455 const uno::Reference
< io::XInputStream
> & xStream
,
1456 uno::Sequence
< sal_Int8
> & rData
,
1457 bool bAppendTrailingZeroByte
)
1461 uno::Reference
< io::XSeekable
> xSeekable( xStream
, uno::UNO_QUERY
);
1462 if ( xSeekable
.is() )
1467 = sal::static_int_cast
<sal_Int32
>(xSeekable
->getLength());
1469 = xStream
->readBytes( rData
, nSize
);
1471 if ( nRead
== nSize
)
1473 if ( bAppendTrailingZeroByte
)
1475 rData
.realloc( nSize
+ 1 );
1476 rData
[ nSize
] = sal_Int8( 0 );
1481 catch ( io::NotConnectedException
const & )
1485 catch ( io::BufferSizeExceededException
const & )
1489 catch ( io::IOException
const & )
1491 // getLength, readBytes
1498 uno::Sequence
< sal_Int8
> aBuffer
;
1501 sal_Int32 nRead
= xStream
->readSomeBytes( aBuffer
, 65536 );
1504 if ( rData
.getLength() < ( nPos
+ nRead
) )
1505 rData
.realloc( nPos
+ nRead
);
1507 aBuffer
.realloc( nRead
);
1508 memcpy( (void*)( rData
.getArray() + nPos
),
1509 (const void*)aBuffer
.getConstArray(),
1513 aBuffer
.realloc( 0 );
1514 nRead
= xStream
->readSomeBytes( aBuffer
, 65536 );
1517 if ( bAppendTrailingZeroByte
)
1519 rData
.realloc( nPos
+ 1 );
1520 rData
[ nPos
] = sal_Int8( 0 );
1524 catch ( io::NotConnectedException
const & )
1528 catch ( io::BufferSizeExceededException
const & )
1532 catch ( io::IOException
const & )
1541 // ---------------------------------------------------------------------
1543 SerfSession::isDomainMatch( OUString certHostName
)
1545 OUString hostName
= getHostName();
1547 if (hostName
.equalsIgnoreAsciiCase( certHostName
) )
1550 if ( 0 == certHostName
.indexOf( OUString::createFromAscii( "*" ) ) &&
1551 hostName
.getLength() >= certHostName
.getLength() )
1553 OUString cmpStr
= certHostName
.copy( 1 );
1555 if ( hostName
.matchIgnoreAsciiCase(
1556 cmpStr
, hostName
.getLength() - cmpStr
.getLength() ) )
1563 // ---------------------------------------------------------------------
1564 OUString SerfSession::makeAbsoluteURL( OUString const & rURL ) const
1568 // Is URL relative or already absolute?
1569 if ( rURL[ 0 ] != sal_Unicode( '/' ) )
1572 return OUString( rURL );
1577 memset( &aUri, 0, sizeof( aUri ) );
1579 ne_fill_server_uri( m_pHttpSession, &aUri );
1581 = ne_strdup( OUStringToOString(
1582 rURL, RTL_TEXTENCODING_UTF8 ).getStr() );
1583 SerfUri aSerfUri( &aUri );
1584 ne_uri_free( &aUri );
1585 return aSerfUri.GetURI();
1588 catch ( DAVException const & )
1596 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */