1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include <boost/unordered_map.hpp>
33 #include "osl/diagnose.h"
35 #include <rtl/string.h>
36 #include <ne_socket.h>
38 #include <ne_redirect.h>
41 #if NEON_VERSION < 0x0260
42 // old neon versions forgot to set this
45 #include <ne_compress.h>
46 #if NEON_VERSION < 0x0260
50 #include "libxml/parser.h"
51 #include "rtl/ustrbuf.hxx"
52 #include "comphelper/sequence.hxx"
53 #include <comphelper/stl_types.hxx>
54 #include "ucbhelper/simplecertificatevalidationrequest.hxx"
56 #include "DAVAuthListener.hxx"
57 #include "NeonTypes.hxx"
58 #include "NeonSession.hxx"
59 #include "NeonInputStream.hxx"
60 #include "NeonPropFindRequest.hxx"
61 #include "NeonHeadRequest.hxx"
62 #include "NeonUri.hxx"
63 #include "LinkSequence.hxx"
64 #include "UCBDeadPropertyValue.hxx"
66 #include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
67 #include <com/sun/star/security/XCertificate.hpp>
68 #include <com/sun/star/security/CertificateValidity.hpp>
69 #include <com/sun/star/security/CertificateContainerStatus.hpp>
70 #include <com/sun/star/security/CertificateContainer.hpp>
71 #include <com/sun/star/security/XCertificateContainer.hpp>
72 #include <com/sun/star/ucb/Lock.hpp>
73 #include <com/sun/star/beans/NamedValue.hpp>
74 #include <com/sun/star/xml/crypto/XSEInitializer.hpp>
76 #include <boost/bind.hpp>
78 using namespace com::sun::star
;
79 using namespace webdav_ucp
;
81 #define SEINITIALIZER_COMPONENT "com.sun.star.xml.crypto.SEInitializer"
87 // -------------------------------------------------------------------
89 // -------------------------------------------------------------------
94 rtl::OUString aContentType
;
95 rtl::OUString aReferer
;
98 RequestData( const rtl::OUString
& rContentType
,
99 const rtl::OUString
& rReferer
)
100 : aContentType( rContentType
), aReferer( rReferer
) {}
103 // -------------------------------------------------------------------
105 // -------------------------------------------------------------------
109 bool operator()( const ne_request
* p1
, const ne_request
* p2
) const
117 size_t operator()( const ne_request
* p
) const
123 typedef boost::unordered_map
132 // -------------------------------------------------------------------
134 // -------------------------------------------------------------------
135 static sal_uInt16
makeStatusCode( const rtl::OUString
& rStatusText
)
137 // Extract status code from session error string. Unfortunately
138 // neon provides no direct access to the status code...
140 if ( rStatusText
.getLength() < 3 )
143 "makeStatusCode - status text string to short!" );
147 sal_Int32 nPos
= rStatusText
.indexOf( ' ' );
150 OSL_FAIL( "makeStatusCode - wrong status text format!" );
154 return sal_uInt16( rStatusText
.copy( 0, nPos
).toInt32() );
157 // -------------------------------------------------------------------
158 static bool noKeepAlive( const uno::Sequence
< beans::NamedValue
>& rFlags
)
160 if ( !rFlags
.hasElements() )
163 // find "KeepAlive" property
164 const beans::NamedValue
* pAry(rFlags
.getConstArray());
165 const sal_Int32
nLen(rFlags
.getLength());
166 const beans::NamedValue
* pValue(
167 std::find_if(pAry
,pAry
+nLen
,
168 boost::bind(comphelper::TNamedValueEqualFunctor(),
170 rtl::OUString("KeepAlive"))));
171 if ( pValue
!= pAry
+nLen
&& !pValue
->Value
.get
<sal_Bool
>() )
177 // -------------------------------------------------------------------
178 struct NeonRequestContext
180 uno::Reference
< io::XOutputStream
> xOutputStream
;
181 rtl::Reference
< NeonInputStream
> xInputStream
;
182 const std::vector
< ::rtl::OUString
> * pHeaderNames
;
183 DAVResource
* pResource
;
185 NeonRequestContext( uno::Reference
< io::XOutputStream
> & xOutStrm
)
186 : xOutputStream( xOutStrm
), xInputStream( 0 ),
187 pHeaderNames( 0 ), pResource( 0 ) {}
189 NeonRequestContext( const rtl::Reference
< NeonInputStream
> & xInStrm
)
190 : xOutputStream( 0 ), xInputStream( xInStrm
),
191 pHeaderNames( 0 ), pResource( 0 ) {}
193 NeonRequestContext( uno::Reference
< io::XOutputStream
> & xOutStrm
,
194 const std::vector
< ::rtl::OUString
> & inHeaderNames
,
195 DAVResource
& ioResource
)
196 : xOutputStream( xOutStrm
), xInputStream( 0 ),
197 pHeaderNames( &inHeaderNames
), pResource( &ioResource
) {}
199 NeonRequestContext( const rtl::Reference
< NeonInputStream
> & xInStrm
,
200 const std::vector
< ::rtl::OUString
> & inHeaderNames
,
201 DAVResource
& ioResource
)
202 : xOutputStream( 0 ), xInputStream( xInStrm
),
203 pHeaderNames( &inHeaderNames
), pResource( &ioResource
) {}
206 //--------------------------------------------------------------------
207 //--------------------------------------------------------------------
209 // Callback functions
211 //--------------------------------------------------------------------
212 //--------------------------------------------------------------------
214 // -------------------------------------------------------------------
215 // ResponseBlockReader
216 // A simple Neon response_block_reader for use with an XInputStream
217 // -------------------------------------------------------------------
219 extern "C" int NeonSession_ResponseBlockReader(void * inUserData
,
223 // neon sometimes calls this function with (inLen == 0)...
226 NeonRequestContext
* pCtx
227 = static_cast< NeonRequestContext
* >( inUserData
);
229 rtl::Reference
< NeonInputStream
> xInputStream(
230 pCtx
->xInputStream
);
232 if ( xInputStream
.is() )
233 xInputStream
->AddToStream( inBuf
, inLen
);
238 // -------------------------------------------------------------------
239 // ResponseBlockWriter
240 // A simple Neon response_block_reader for use with an XOutputStream
241 // -------------------------------------------------------------------
243 extern "C" int NeonSession_ResponseBlockWriter( void * inUserData
,
247 // neon calls this function with (inLen == 0)...
250 NeonRequestContext
* pCtx
251 = static_cast< NeonRequestContext
* >( inUserData
);
252 uno::Reference
< io::XOutputStream
> xOutputStream
253 = pCtx
->xOutputStream
;
255 if ( xOutputStream
.is() )
257 const uno::Sequence
< sal_Int8
> aSeq( (sal_Int8
*)inBuf
, inLen
);
258 xOutputStream
->writeBytes( aSeq
);
264 // -------------------------------------------------------------------
265 extern "C" int NeonSession_NeonAuth( void * inUserData
,
266 #ifdef NE_FEATURE_SSPI
267 const char * inAuthProtocol
,
269 const char * inRealm
,
271 char * inoutUserName
,
272 char * inoutPassWord
)
274 /* The callback used to request the username and password in the given
275 * realm. The username and password must be copied into the buffers
276 * which are both of size NE_ABUFSIZ. The 'attempt' parameter is zero
277 * on the first call to the callback, and increases by one each time
278 * an attempt to authenticate fails.
280 * The callback must return zero to indicate that authentication
281 * should be attempted with the username/password, or non-zero to
282 * cancel the request. (if non-zero, username and password are
285 NeonSession
* theSession
= static_cast< NeonSession
* >( inUserData
);
286 DAVAuthListener
* pListener
287 = theSession
->getRequestEnvironment().m_xAuthListener
.get();
293 rtl::OUString theUserName
;
294 rtl::OUString thePassWord
;
298 // neon does not handle username supplied with request URI (for
299 // instance when doing FTP over proxy - last checked: 0.23.5 )
303 NeonUri
uri( theSession
->getRequestEnvironment().m_aRequestURI
);
304 rtl::OUString
aUserInfo( uri
.GetUserInfo() );
305 if ( !aUserInfo
.isEmpty() )
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 & )
327 // username buffer is prefilled with user name from last attempt.
328 theUserName
= rtl::OUString::createFromAscii( inoutUserName
);
329 // @@@ Neon does not initialize password buffer (last checked: 0.22.0).
330 //thePassWord = rtl::OUString::createFromAscii( inoutPassWord );
333 bool bCanUseSystemCreds
= false;
335 #ifdef NE_FEATURE_SSPI
337 = (attempt
== 0) && // avoid endless loops
338 ne_has_support( NE_FEATURE_SSPI
) && // Windows-only feature.
339 ( ( ne_strcasecmp( inAuthProtocol
, "NTLM" ) == 0 ) ||
340 ( ne_strcasecmp( inAuthProtocol
, "Negotiate" ) == 0 ) );
343 int theRetVal
= pListener
->authenticate(
344 rtl::OUString::createFromAscii( inRealm
),
345 theSession
->getHostName(),
351 rtl::OUStringToOString( theUserName
, RTL_TEXTENCODING_UTF8
) );
352 if ( aUser
.getLength() > ( NE_ABUFSIZ
- 1 ) )
355 "NeonSession_NeonAuth - username to long!" );
360 rtl::OUStringToOString( thePassWord
, RTL_TEXTENCODING_UTF8
) );
361 if ( aPass
.getLength() > ( NE_ABUFSIZ
- 1 ) )
364 "NeonSession_NeonAuth - password to long!" );
368 strcpy( inoutUserName
, // #100211# - checked
369 rtl::OUStringToOString( theUserName
, RTL_TEXTENCODING_UTF8
).getStr() );
371 strcpy( inoutPassWord
, // #100211# - checked
372 rtl::OUStringToOString( thePassWord
, RTL_TEXTENCODING_UTF8
).getStr() );
377 // -------------------------------------------------------------------
380 // -------------------------------------------------------------------
382 ::rtl::OUString
GetHostnamePart( const ::rtl::OUString
& _rRawString
)
384 ::rtl::OUString sPart
;
385 ::rtl::OUString
sPartId("CN=");
386 sal_Int32 nContStart
= _rRawString
.indexOf( sPartId
);
387 if ( nContStart
!= -1 )
389 nContStart
= nContStart
+ sPartId
.getLength();
391 = _rRawString
.indexOf( sal_Unicode( ',' ), nContStart
);
392 sPart
= _rRawString
.copy( nContStart
, nContEnd
- nContStart
);
398 // -------------------------------------------------------------------
399 extern "C" int NeonSession_CertificationNotify( void *userdata
,
401 const ne_ssl_certificate
*cert
)
405 NeonSession
* pSession
= static_cast< NeonSession
* >( userdata
);
406 uno::Reference
< security::XCertificateContainer
> xCertificateContainer
;
409 xCertificateContainer
410 = uno::Reference
< security::XCertificateContainer
>(
411 pSession
->getMSF()->createInstance(
412 rtl::OUString( "com.sun.star.security.CertificateContainer" ) ),
415 catch ( uno::Exception
const & )
419 if ( !xCertificateContainer
.is() )
424 char * dn
= ne_ssl_readable_dname( ne_ssl_cert_subject( cert
) );
425 rtl::OUString
cert_subject( dn
, strlen( dn
), RTL_TEXTENCODING_UTF8
, 0 );
429 security::CertificateContainerStatus
certificateContainer(
430 xCertificateContainer
->hasCertificate(
431 pSession
->getHostName(), cert_subject
) );
433 if ( certificateContainer
!= security::CertificateContainerStatus_NOCERT
)
435 certificateContainer
== security::CertificateContainerStatus_TRUSTED
439 uno::Reference
< xml::crypto::XSEInitializer
> xSEInitializer
;
442 xSEInitializer
= uno::Reference
< xml::crypto::XSEInitializer
>(
443 pSession
->getMSF()->createInstance(
444 rtl::OUString( SEINITIALIZER_COMPONENT
) ),
447 catch ( uno::Exception
const & )
451 if ( !xSEInitializer
.is() )
454 uno::Reference
< xml::crypto::XXMLSecurityContext
> xSecurityContext(
455 xSEInitializer
->createSecurityContext( rtl::OUString() ) );
457 uno::Reference
< xml::crypto::XSecurityEnvironment
> xSecurityEnv(
458 xSecurityContext
->getSecurityEnvironment() );
460 //The end entity certificate
461 char * eeCertB64
= ne_ssl_cert_export( cert
);
463 rtl::OString
sEECertB64( eeCertB64
);
465 uno::Reference
< security::XCertificate
> xEECert(
466 xSecurityEnv
->createCertificateFromAscii(
467 rtl::OStringToOUString( sEECertB64
, RTL_TEXTENCODING_ASCII_US
) ) );
469 ne_free( eeCertB64
);
472 std::vector
< uno::Reference
< security::XCertificate
> > vecCerts
;
473 const ne_ssl_certificate
* issuerCert
= cert
;
476 //get the intermediate certificate
477 //the returned value is const ! Therfore it does not need to be freed
478 //with ne_ssl_cert_free, which takes a non-const argument
479 issuerCert
= ne_ssl_cert_signedby( issuerCert
);
480 if ( NULL
== issuerCert
)
483 char * imCertB64
= ne_ssl_cert_export( issuerCert
);
484 rtl::OString
sInterMediateCertB64( imCertB64
);
485 ne_free( imCertB64
);
487 uno::Reference
< security::XCertificate
> xImCert(
488 xSecurityEnv
->createCertificateFromAscii(
489 rtl::OStringToOUString( sInterMediateCertB64
, RTL_TEXTENCODING_ASCII_US
) ) );
491 vecCerts
.push_back( xImCert
);
495 sal_Int64 certValidity
= xSecurityEnv
->verifyCertificate( xEECert
,
496 ::comphelper::containerToSequence( vecCerts
) );
498 if ( pSession
->isDomainMatch(
499 GetHostnamePart( xEECert
.get()->getSubjectName() ) ) )
501 // if host name matched with certificate then look if the
502 // certificate was ok
503 if( certValidity
== security::CertificateValidity::VALID
)
507 const uno::Reference
< ucb::XCommandEnvironment
> xEnv(
508 pSession
->getRequestEnvironment().m_xEnv
);
511 failures
= static_cast< int >( certValidity
);
513 uno::Reference
< task::XInteractionHandler
> xIH(
514 xEnv
->getInteractionHandler() );
517 rtl::Reference
< ucbhelper::SimpleCertificateValidationRequest
>
518 xRequest( new ucbhelper::SimpleCertificateValidationRequest(
519 (sal_Int32
)failures
, xEECert
, pSession
->getHostName() ) );
520 xIH
->handle( xRequest
.get() );
522 rtl::Reference
< ucbhelper::InteractionContinuation
> xSelection
523 = xRequest
->getSelection();
525 if ( xSelection
.is() )
527 uno::Reference
< task::XInteractionApprove
> xApprove(
528 xSelection
.get(), uno::UNO_QUERY
);
531 xCertificateContainer
->addCertificate(
532 pSession
->getHostName(), cert_subject
, sal_True
);
538 xCertificateContainer
->addCertificate(
539 pSession
->getHostName(), cert_subject
, sal_False
);
547 xCertificateContainer
->addCertificate(
548 pSession
->getHostName(), cert_subject
, sal_False
);
555 // -------------------------------------------------------------------
556 extern "C" void NeonSession_PreSendRequest( ne_request
* req
,
558 ne_buffer
* headers
)
560 // userdata -> value returned by 'create'
562 NeonSession
* pSession
= static_cast< NeonSession
* >( userdata
);
565 // If there is a proxy server in between, it shall never use
566 // cached data. We always want 'up-to-date' data.
567 ne_buffer_concat( headers
, "Pragma: no-cache", EOL
, NULL
);
568 // alternative, but understoud by HTTP 1.1 servers only:
569 // ne_buffer_concat( headers, "Cache-Control: max-age=0", EOL, NULL );
571 const RequestDataMap
* pRequestData
572 = static_cast< const RequestDataMap
* >(
573 pSession
->getRequestData() );
575 RequestDataMap::const_iterator it
= pRequestData
->find( req
);
576 if ( it
!= pRequestData
->end() )
578 if ( !(*it
).second
.aContentType
.isEmpty() )
580 char * pData
= headers
->data
;
581 if ( strstr( pData
, "Content-Type:" ) == NULL
)
584 = rtl::OUStringToOString( (*it
).second
.aContentType
,
585 RTL_TEXTENCODING_UTF8
);
586 ne_buffer_concat( headers
, "Content-Type: ",
587 aType
.getStr(), EOL
, NULL
);
591 if ( !(*it
).second
.aReferer
.isEmpty() )
593 char * pData
= headers
->data
;
594 if ( strstr( pData
, "Referer:" ) == NULL
)
596 rtl::OString aReferer
597 = rtl::OUStringToOString( (*it
).second
.aReferer
,
598 RTL_TEXTENCODING_UTF8
);
599 ne_buffer_concat( headers
, "Referer: ",
600 aReferer
.getStr(), EOL
, NULL
);
605 const DAVRequestHeaders
& rHeaders
606 = pSession
->getRequestEnvironment().m_aRequestHeaders
;
608 DAVRequestHeaders::const_iterator
it1( rHeaders
.begin() );
609 const DAVRequestHeaders::const_iterator
end1( rHeaders
.end() );
611 while ( it1
!= end1
)
614 = rtl::OUStringToOString( (*it1
).first
,
615 RTL_TEXTENCODING_UTF8
);
617 = rtl::OUStringToOString( (*it1
).second
,
618 RTL_TEXTENCODING_UTF8
);
619 ne_buffer_concat( headers
, aHeader
.getStr(), ": ",
620 aValue
.getStr(), EOL
, NULL
);
627 // -------------------------------------------------------------------
629 bool NeonSession::m_bGlobalsInited
= false;
630 //See https://bugzilla.redhat.com/show_bug.cgi?id=544619#c4
631 //neon is threadsafe, but uses gnutls which is only thread-safe
632 //if initialized to be thread-safe. cups, unfortunately, generally
633 //initializes it first, and as non-thread-safe, leaving the entire
635 osl::Mutex aGlobalNeonMutex
;
636 NeonLockStore
NeonSession::m_aNeonLockStore
;
638 // -------------------------------------------------------------------
640 // -------------------------------------------------------------------
641 NeonSession::NeonSession(
642 const rtl::Reference
< DAVSessionFactory
> & rSessionFactory
,
643 const rtl::OUString
& inUri
,
644 const uno::Sequence
< beans::NamedValue
>& rFlags
,
645 const ucbhelper::InternetProxyDecider
& rProxyDecider
)
646 throw ( DAVException
)
647 : DAVSession( rSessionFactory
),
650 m_pRequestData( new RequestDataMap
),
651 m_rProxyDecider( rProxyDecider
)
653 NeonUri
theUri( inUri
);
654 m_aScheme
= theUri
.GetScheme();
655 m_aHostName
= theUri
.GetHost();
656 m_nPort
= theUri
.GetPort();
659 // -------------------------------------------------------------------
661 // -------------------------------------------------------------------
662 NeonSession::~NeonSession( )
664 if ( m_pHttpSession
)
667 osl::Guard
< osl::Mutex
> theGlobalGuard( aGlobalNeonMutex
);
668 ne_session_destroy( m_pHttpSession
);
672 delete static_cast< RequestDataMap
* >( m_pRequestData
);
675 // -------------------------------------------------------------------
676 void NeonSession::Init( const DAVRequestEnvironment
& rEnv
)
677 throw ( DAVException
)
679 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
684 // -------------------------------------------------------------------
685 void NeonSession::Init()
686 throw ( DAVException
)
688 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
690 bool bCreateNewSession
= false;
692 if ( m_pHttpSession
== 0 )
694 // Ensure that Neon sockets are initialized
695 osl::Guard
< osl::Mutex
> theGlobalGuard( aGlobalNeonMutex
);
696 if ( !m_bGlobalsInited
)
698 if ( ne_sock_init() != 0 )
699 throw DAVException( DAVException::DAV_SESSION_CREATE
,
700 NeonUri::makeConnectionEndPointString(
701 m_aHostName
, m_nPort
) );
703 // #122205# - libxml2 needs to be initialized once if used by
704 // multithreaded programs like OOo.
706 #if OSL_DEBUG_LEVEL > 0
707 // for more debug flags see ne_utils.h; NE_DEBUGGING must be defined
708 // while compiling neon in order to actually activate neon debug
710 ne_debug_init( stderr
, NE_DBG_FLUSH
720 m_bGlobalsInited
= true;
723 const ucbhelper::InternetProxyServer
& rProxyCfg
= getProxySettings();
725 m_aProxyName
= rProxyCfg
.aName
;
726 m_nProxyPort
= rProxyCfg
.nPort
;
728 // Not yet initialized. Create new session.
729 bCreateNewSession
= true;
733 // #112271# Check whether proxy settings are still valid (They may
734 // change at any time). If not, create new Neon session.
736 const ucbhelper::InternetProxyServer
& rProxyCfg
= getProxySettings();
738 if ( ( rProxyCfg
.aName
!= m_aProxyName
)
739 || ( rProxyCfg
.nPort
!= m_nProxyPort
) )
741 m_aProxyName
= rProxyCfg
.aName
;
742 m_nProxyPort
= rProxyCfg
.nPort
;
744 // new session needed, destroy old first
746 osl::Guard
< osl::Mutex
> theGlobalGuard( aGlobalNeonMutex
);
747 ne_session_destroy( m_pHttpSession
);
750 bCreateNewSession
= true;
754 if ( bCreateNewSession
)
756 // @@@ For FTP over HTTP proxy inUserInfo is needed to be able to
757 // build the complete request URI (including user:pass), but
758 // currently (0.22.0) neon does not allow to pass the user info
762 osl::Guard
< osl::Mutex
> theGlobalGuard( aGlobalNeonMutex
);
763 m_pHttpSession
= ne_session_create(
764 rtl::OUStringToOString( m_aScheme
, RTL_TEXTENCODING_UTF8
).getStr(),
765 /* theUri.GetUserInfo(),
766 @@@ for FTP via HTTP proxy, but not supported by Neon */
767 rtl::OUStringToOString( m_aHostName
, RTL_TEXTENCODING_UTF8
).getStr(),
771 if ( m_pHttpSession
== 0 )
772 throw DAVException( DAVException::DAV_SESSION_CREATE
,
773 NeonUri::makeConnectionEndPointString(
774 m_aHostName
, m_nPort
) );
776 // Register the session with the lock store
777 m_aNeonLockStore
.registerSession( m_pHttpSession
);
779 if ( m_aScheme
.equalsIgnoreAsciiCase(
780 rtl::OUString( "https" ) ) )
782 // Set a failure callback for certificate check
784 m_pHttpSession
, NeonSession_CertificationNotify
, this);
786 ne_ssl_trust_default_ca(m_pHttpSession
);
789 // Add hooks (i.e. for adding additional headers to the request)
792 /* Hook called when a request is created. */
793 //typedef void (*ne_create_request_fn)(ne_request *req, void *userdata,
794 // const char *method, const char *path);
796 ne_hook_create_request( m_pHttpSession
, create_req_hook_fn
, this );
799 /* Hook called before the request is sent. 'header' is the raw HTTP
800 * header before the trailing CRLF is added: add in more here. */
801 //typedef void (*ne_pre_send_fn)(ne_request *req, void *userdata,
802 // ne_buffer *header);
804 ne_hook_pre_send( m_pHttpSession
, NeonSession_PreSendRequest
, this );
806 /* Hook called after the request is sent. May return:
807 * NE_OK everything is okay
808 * NE_RETRY try sending the request again.
809 * anything else signifies an error, and the request is failed. The
810 * return code is passed back the _dispatch caller, so the session error
811 * must also be set appropriately (ne_set_error).
813 //typedef int (*ne_post_send_fn)(ne_request *req, void *userdata,
814 // const ne_status *status);
816 ne_hook_post_send( m_pHttpSession
, post_send_req_hook_fn
, this );
818 /* Hook called when the request is destroyed. */
819 //typedef void (*ne_destroy_req_fn)(ne_request *req, void *userdata);
821 ne_hook_destroy_request( m_pHttpSession
, destroy_req_hook_fn
, this );
823 /* Hook called when the session is destroyed. */
824 //typedef void (*ne_destroy_sess_fn)(void *userdata);
826 ne_hook_destroy_session( m_pHttpSession
, destroy_sess_hook_fn
, this );
829 if ( !m_aProxyName
.isEmpty() )
831 ne_session_proxy( m_pHttpSession
,
832 rtl::OUStringToOString(
834 RTL_TEXTENCODING_UTF8
).getStr(),
839 if ( noKeepAlive(m_aFlags
) )
840 ne_set_session_flag( m_pHttpSession
, NE_SESSFLAG_PERSIST
, 0 );
842 // Register for redirects.
843 ne_redirect_register( m_pHttpSession
);
845 // authentication callbacks.
846 #if NEON_VERSION >= 0x0260
847 ne_add_server_auth( m_pHttpSession
, NE_AUTH_ALL
, NeonSession_NeonAuth
, this );
848 ne_add_proxy_auth ( m_pHttpSession
, NE_AUTH_ALL
, NeonSession_NeonAuth
, this );
850 ne_set_server_auth( m_pHttpSession
, NeonSession_NeonAuth
, this );
851 ne_set_proxy_auth ( m_pHttpSession
, NeonSession_NeonAuth
, this );
856 // -------------------------------------------------------------------
858 sal_Bool
NeonSession::CanUse( const rtl::OUString
& inUri
,
859 const uno::Sequence
< beans::NamedValue
>& rFlags
)
863 NeonUri
theUri( inUri
);
864 if ( ( theUri
.GetPort() == m_nPort
) &&
865 ( theUri
.GetHost() == m_aHostName
) &&
866 ( theUri
.GetScheme() == m_aScheme
) &&
867 ( rFlags
== m_aFlags
) )
870 catch ( DAVException
const & )
877 // -------------------------------------------------------------------
879 sal_Bool
NeonSession::UsesProxy()
882 return !m_aProxyName
.isEmpty() ;
885 // -------------------------------------------------------------------
887 // -------------------------------------------------------------------
888 void NeonSession::OPTIONS( const rtl::OUString
& inPath
,
889 DAVCapabilities
& outCapabilities
,
890 const DAVRequestEnvironment
& rEnv
)
891 throw( DAVException
)
893 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
897 HttpServerCapabilities servercaps
;
898 memset( &servercaps
, 0, sizeof( servercaps
) );
900 int theRetVal
= ne_options( m_pHttpSession
,
901 rtl::OUStringToOString(
902 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
905 HandleError( theRetVal
, inPath
, rEnv
);
907 outCapabilities
.class1
= !!servercaps
.dav_class1
;
908 outCapabilities
.class2
= !!servercaps
.dav_class2
;
909 outCapabilities
.executable
= !!servercaps
.dav_executable
;
912 // -------------------------------------------------------------------
913 // PROPFIND - allprop & named
914 // -------------------------------------------------------------------
915 void NeonSession::PROPFIND( const rtl::OUString
& inPath
,
917 const std::vector
< rtl::OUString
> & inPropNames
,
918 std::vector
< DAVResource
> & ioResources
,
919 const DAVRequestEnvironment
& rEnv
)
920 throw ( DAVException
)
922 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
926 int theRetVal
= NE_OK
;
927 NeonPropFindRequest
theRequest( m_pHttpSession
,
928 rtl::OUStringToOString(
929 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
935 HandleError( theRetVal
, inPath
, rEnv
);
938 // -------------------------------------------------------------------
939 // PROPFIND - propnames
940 // -------------------------------------------------------------------
941 void NeonSession::PROPFIND( const rtl::OUString
& inPath
,
943 std::vector
< DAVResourceInfo
> & ioResInfo
,
944 const DAVRequestEnvironment
& rEnv
)
945 throw( DAVException
)
947 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
951 int theRetVal
= NE_OK
;
952 NeonPropFindRequest
theRequest( m_pHttpSession
,
953 rtl::OUStringToOString(
954 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
959 HandleError( theRetVal
, inPath
, rEnv
);
962 // -------------------------------------------------------------------
964 // -------------------------------------------------------------------
965 void NeonSession::PROPPATCH( const rtl::OUString
& inPath
,
966 const std::vector
< ProppatchValue
> & inValues
,
967 const DAVRequestEnvironment
& rEnv
)
968 throw( DAVException
)
970 /* @@@ Which standard live properties can be set by the client?
971 This is a known WebDAV RFC issue ( verified: 04/10/2001 )
972 --> http://www.ics.uci.edu/pub/ietf/webdav/protocol/issues.html
974 mod_dav implementation:
976 creationdate r ( File System prop )
978 getcontentlanguage r ( #ifdef DAV_DISABLE_WRITEABLE_PROPS )
979 getcontentlength r ( File System prop )
980 getcontenttype r ( #ifdef DAV_DISABLE_WRITEABLE_PROPS )
981 getetag r ( File System prop )
982 getlastmodified r ( File System prop )
987 executable w ( #ifndef WIN32 )
989 All dead properties are of course writable.
992 int theRetVal
= NE_OK
;
994 int n
; // for the "for" loop
996 // Generate the list of properties we want to set.
997 int nPropCount
= inValues
.size();
998 ne_proppatch_operation
* pItems
999 = new ne_proppatch_operation
[ nPropCount
+ 1 ];
1000 for ( n
= 0; n
< nPropCount
; ++n
)
1002 const ProppatchValue
& rValue
= inValues
[ n
];
1004 // Split fullname into namespace and name!
1005 ne_propname
* pName
= new ne_propname
;
1006 DAVProperties::createNeonPropName( rValue
.name
, *pName
);
1007 pItems
[ n
].name
= pName
;
1009 if ( rValue
.operation
== PROPSET
)
1011 pItems
[ n
].type
= ne_propset
;
1013 rtl::OUString aStringValue
;
1014 if ( DAVProperties::isUCBDeadProperty( *pName
) )
1016 // DAV dead property added by WebDAV UCP?
1017 if ( !UCBDeadPropertyValue::toXML( rValue
.value
,
1021 pItems
[ n
].value
= 0;
1022 theRetVal
= NE_ERROR
;
1027 else if ( !( rValue
.value
>>= aStringValue
) )
1029 // complex properties...
1030 if ( rValue
.name
== DAVProperties::SOURCE
)
1032 uno::Sequence
< ucb::Link
> aLinks
;
1033 if ( rValue
.value
>>= aLinks
)
1035 LinkSequence::toXML( aLinks
, aStringValue
);
1040 pItems
[ n
].value
= 0;
1041 theRetVal
= NE_ERROR
;
1048 OSL_FAIL( "NeonSession::PROPPATCH - unsupported type!" );
1050 pItems
[ n
].value
= 0;
1051 theRetVal
= NE_ERROR
;
1057 = strdup( rtl::OUStringToOString( aStringValue
,
1058 RTL_TEXTENCODING_UTF8
).getStr() );
1062 pItems
[ n
].type
= ne_propremove
;
1063 pItems
[ n
].value
= 0;
1067 if ( theRetVal
== NE_OK
)
1069 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1073 pItems
[ n
].name
= 0;
1075 theRetVal
= ne_proppatch( m_pHttpSession
,
1076 rtl::OUStringToOString(
1077 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1081 for ( n
= 0; n
< nPropCount
; ++n
)
1083 free( (void *)pItems
[ n
].name
->name
);
1084 delete pItems
[ n
].name
;
1085 free( (void *)pItems
[ n
].value
);
1090 HandleError( theRetVal
, inPath
, rEnv
);
1093 // -------------------------------------------------------------------
1095 // -------------------------------------------------------------------
1096 void NeonSession::HEAD( const ::rtl::OUString
& inPath
,
1097 const std::vector
< ::rtl::OUString
> & inHeaderNames
,
1098 DAVResource
& ioResource
,
1099 const DAVRequestEnvironment
& rEnv
)
1100 throw( DAVException
)
1102 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1106 int theRetVal
= NE_OK
;
1107 NeonHeadRequest
theRequest( m_pHttpSession
,
1113 HandleError( theRetVal
, inPath
, rEnv
);
1116 // -------------------------------------------------------------------
1118 // -------------------------------------------------------------------
1119 uno::Reference
< io::XInputStream
>
1120 NeonSession::GET( const rtl::OUString
& inPath
,
1121 const DAVRequestEnvironment
& rEnv
)
1122 throw ( DAVException
)
1124 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1128 rtl::Reference
< NeonInputStream
> xInputStream( new NeonInputStream
);
1129 NeonRequestContext
aCtx( xInputStream
);
1130 int theRetVal
= GET( m_pHttpSession
,
1131 rtl::OUStringToOString(
1132 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1133 NeonSession_ResponseBlockReader
,
1137 HandleError( theRetVal
, inPath
, rEnv
);
1139 return uno::Reference
< io::XInputStream
>( xInputStream
.get() );
1142 // -------------------------------------------------------------------
1144 // -------------------------------------------------------------------
1145 void NeonSession::GET( const rtl::OUString
& inPath
,
1146 uno::Reference
< io::XOutputStream
> & ioOutputStream
,
1147 const DAVRequestEnvironment
& rEnv
)
1148 throw ( DAVException
)
1150 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1154 NeonRequestContext
aCtx( ioOutputStream
);
1155 int theRetVal
= GET( m_pHttpSession
,
1156 rtl::OUStringToOString(
1157 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1158 NeonSession_ResponseBlockWriter
,
1162 HandleError( theRetVal
, inPath
, rEnv
);
1165 // -------------------------------------------------------------------
1167 // -------------------------------------------------------------------
1168 uno::Reference
< io::XInputStream
>
1169 NeonSession::GET( const rtl::OUString
& inPath
,
1170 const std::vector
< ::rtl::OUString
> & inHeaderNames
,
1171 DAVResource
& ioResource
,
1172 const DAVRequestEnvironment
& rEnv
)
1173 throw ( DAVException
)
1175 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1179 ioResource
.uri
= inPath
;
1180 ioResource
.properties
.clear();
1182 rtl::Reference
< NeonInputStream
> xInputStream( new NeonInputStream
);
1183 NeonRequestContext
aCtx( xInputStream
, inHeaderNames
, ioResource
);
1184 int theRetVal
= GET( m_pHttpSession
,
1185 rtl::OUStringToOString(
1186 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1187 NeonSession_ResponseBlockReader
,
1191 HandleError( theRetVal
, inPath
, rEnv
);
1193 return uno::Reference
< io::XInputStream
>( xInputStream
.get() );
1196 // -------------------------------------------------------------------
1198 // -------------------------------------------------------------------
1199 void NeonSession::GET( const rtl::OUString
& inPath
,
1200 uno::Reference
< io::XOutputStream
> & ioOutputStream
,
1201 const std::vector
< ::rtl::OUString
> & inHeaderNames
,
1202 DAVResource
& ioResource
,
1203 const DAVRequestEnvironment
& rEnv
)
1204 throw ( DAVException
)
1206 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1210 ioResource
.uri
= inPath
;
1211 ioResource
.properties
.clear();
1213 NeonRequestContext
aCtx( ioOutputStream
, inHeaderNames
, ioResource
);
1214 int theRetVal
= GET( m_pHttpSession
,
1215 rtl::OUStringToOString(
1216 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1217 NeonSession_ResponseBlockWriter
,
1221 HandleError( theRetVal
, inPath
, rEnv
);
1224 // -------------------------------------------------------------------
1226 // -------------------------------------------------------------------
1227 void NeonSession::PUT( const rtl::OUString
& inPath
,
1228 const uno::Reference
< io::XInputStream
> & inInputStream
,
1229 const DAVRequestEnvironment
& rEnv
)
1230 throw ( DAVException
)
1232 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1234 uno::Sequence
< sal_Int8
> aDataToSend
;
1235 if ( !getDataFromInputStream( inInputStream
, aDataToSend
, false ) )
1236 throw DAVException( DAVException::DAV_INVALID_ARG
);
1240 int theRetVal
= PUT( m_pHttpSession
,
1241 rtl::OUStringToOString(
1242 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1243 reinterpret_cast< const char * >(
1244 aDataToSend
.getConstArray() ),
1245 aDataToSend
.getLength() );
1247 HandleError( theRetVal
, inPath
, rEnv
);
1250 // -------------------------------------------------------------------
1252 // -------------------------------------------------------------------
1253 uno::Reference
< io::XInputStream
>
1254 NeonSession::POST( const rtl::OUString
& inPath
,
1255 const rtl::OUString
& rContentType
,
1256 const rtl::OUString
& rReferer
,
1257 const uno::Reference
< io::XInputStream
> & inInputStream
,
1258 const DAVRequestEnvironment
& rEnv
)
1259 throw ( DAVException
)
1261 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1263 uno::Sequence
< sal_Int8
> aDataToSend
;
1264 if ( !getDataFromInputStream( inInputStream
, aDataToSend
, true ) )
1265 throw DAVException( DAVException::DAV_INVALID_ARG
);
1269 rtl::Reference
< NeonInputStream
> xInputStream( new NeonInputStream
);
1270 NeonRequestContext
aCtx( xInputStream
);
1271 int theRetVal
= POST( m_pHttpSession
,
1272 rtl::OUStringToOString(
1273 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1274 reinterpret_cast< const char * >(
1275 aDataToSend
.getConstArray() ),
1276 NeonSession_ResponseBlockReader
,
1281 HandleError( theRetVal
, inPath
, rEnv
);
1283 return uno::Reference
< io::XInputStream
>( xInputStream
.get() );
1286 // -------------------------------------------------------------------
1288 // -------------------------------------------------------------------
1289 void NeonSession::POST( const rtl::OUString
& inPath
,
1290 const rtl::OUString
& rContentType
,
1291 const rtl::OUString
& rReferer
,
1292 const uno::Reference
< io::XInputStream
> & inInputStream
,
1293 uno::Reference
< io::XOutputStream
> & oOutputStream
,
1294 const DAVRequestEnvironment
& rEnv
)
1295 throw ( DAVException
)
1297 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1299 uno::Sequence
< sal_Int8
> aDataToSend
;
1300 if ( !getDataFromInputStream( inInputStream
, aDataToSend
, true ) )
1301 throw DAVException( DAVException::DAV_INVALID_ARG
);
1305 NeonRequestContext
aCtx( oOutputStream
);
1306 int theRetVal
= POST( m_pHttpSession
,
1307 rtl::OUStringToOString(
1308 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1309 reinterpret_cast< const char * >(
1310 aDataToSend
.getConstArray() ),
1311 NeonSession_ResponseBlockWriter
,
1316 HandleError( theRetVal
, inPath
, rEnv
);
1319 // -------------------------------------------------------------------
1321 // -------------------------------------------------------------------
1322 void NeonSession::MKCOL( const rtl::OUString
& inPath
,
1323 const DAVRequestEnvironment
& rEnv
)
1324 throw ( DAVException
)
1326 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1330 int theRetVal
= ne_mkcol( m_pHttpSession
,
1331 rtl::OUStringToOString(
1332 inPath
, RTL_TEXTENCODING_UTF8
).getStr() );
1334 HandleError( theRetVal
, inPath
, rEnv
);
1337 // -------------------------------------------------------------------
1339 // -------------------------------------------------------------------
1340 void NeonSession::COPY( const rtl::OUString
& inSourceURL
,
1341 const rtl::OUString
& inDestinationURL
,
1342 const DAVRequestEnvironment
& rEnv
,
1343 sal_Bool inOverWrite
)
1344 throw ( DAVException
)
1346 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1350 NeonUri
theSourceUri( inSourceURL
);
1351 NeonUri
theDestinationUri( inDestinationURL
);
1353 int theRetVal
= ne_copy( m_pHttpSession
,
1354 inOverWrite
? 1 : 0,
1356 rtl::OUStringToOString(
1357 theSourceUri
.GetPath(),
1358 RTL_TEXTENCODING_UTF8
).getStr(),
1359 rtl::OUStringToOString(
1360 theDestinationUri
.GetPath(),
1361 RTL_TEXTENCODING_UTF8
).getStr() );
1363 HandleError( theRetVal
, inSourceURL
, rEnv
);
1366 // -------------------------------------------------------------------
1368 // -------------------------------------------------------------------
1369 void NeonSession::MOVE( const rtl::OUString
& inSourceURL
,
1370 const rtl::OUString
& inDestinationURL
,
1371 const DAVRequestEnvironment
& rEnv
,
1372 sal_Bool inOverWrite
)
1373 throw ( DAVException
)
1375 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1379 NeonUri
theSourceUri( inSourceURL
);
1380 NeonUri
theDestinationUri( inDestinationURL
);
1381 int theRetVal
= ne_move( m_pHttpSession
,
1382 inOverWrite
? 1 : 0,
1383 rtl::OUStringToOString(
1384 theSourceUri
.GetPath(),
1385 RTL_TEXTENCODING_UTF8
).getStr(),
1386 rtl::OUStringToOString(
1387 theDestinationUri
.GetPath(),
1388 RTL_TEXTENCODING_UTF8
).getStr() );
1390 HandleError( theRetVal
, inSourceURL
, rEnv
);
1393 // -------------------------------------------------------------------
1395 // -------------------------------------------------------------------
1396 void NeonSession::DESTROY( const rtl::OUString
& inPath
,
1397 const DAVRequestEnvironment
& rEnv
)
1398 throw ( DAVException
)
1400 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1404 int theRetVal
= ne_delete( m_pHttpSession
,
1405 rtl::OUStringToOString(
1406 inPath
, RTL_TEXTENCODING_UTF8
).getStr() );
1408 HandleError( theRetVal
, inPath
, rEnv
);
1411 // -------------------------------------------------------------------
1414 sal_Int32
lastChanceToSendRefreshRequest( TimeValue
const & rStart
,
1418 osl_getSystemTime( &aEnd
);
1420 // Try to estimate a safe absolute time for sending the
1421 // lock refresh request.
1422 sal_Int32 lastChanceToSendRefreshRequest
= -1;
1423 if ( timeout
!= NE_TIMEOUT_INFINITE
)
1425 sal_Int32 calltime
= aEnd
.Seconds
- rStart
.Seconds
;
1426 if ( calltime
<= timeout
)
1428 lastChanceToSendRefreshRequest
1429 = aEnd
.Seconds
+ timeout
- calltime
;
1433 OSL_TRACE( "No chance to refresh lock before timeout!" );
1436 return lastChanceToSendRefreshRequest
;
1441 // -------------------------------------------------------------------
1442 // LOCK (set new lock)
1443 // -------------------------------------------------------------------
1444 void NeonSession::LOCK( const ::rtl::OUString
& inPath
,
1446 const DAVRequestEnvironment
& rEnv
)
1447 throw ( DAVException
)
1449 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1453 /* Create a depth zero, exclusive write lock, with default timeout
1454 * (allowing a server to pick a default). token, owner and uri are
1456 NeonLock
* theLock
= ne_lock_create();
1460 ne_uri_parse( rtl::OUStringToOString( makeAbsoluteURL( inPath
),
1461 RTL_TEXTENCODING_UTF8
).getStr(),
1463 theLock
->uri
= aUri
;
1465 // Set the lock depth
1466 switch( rLock
.Depth
)
1468 case ucb::LockDepth_ZERO
:
1469 theLock
->depth
= NE_DEPTH_ZERO
;
1471 case ucb::LockDepth_ONE
:
1472 theLock
->depth
= NE_DEPTH_ONE
;
1474 case ucb::LockDepth_INFINITY
:
1475 theLock
->depth
= NE_DEPTH_INFINITE
;
1478 throw DAVException( DAVException::DAV_INVALID_ARG
);
1481 // Set the lock scope
1482 switch ( rLock
.Scope
)
1484 case ucb::LockScope_EXCLUSIVE
:
1485 theLock
->scope
= ne_lockscope_exclusive
;
1487 case ucb::LockScope_SHARED
:
1488 theLock
->scope
= ne_lockscope_shared
;
1491 throw DAVException( DAVException::DAV_INVALID_ARG
);
1494 // Set the lock timeout
1495 theLock
->timeout
= (long)rLock
.Timeout
;
1497 // Set the lock owner
1498 rtl::OUString aValue
;
1499 rLock
.Owner
>>= aValue
;
1501 ne_strdup( rtl::OUStringToOString( aValue
,
1502 RTL_TEXTENCODING_UTF8
).getStr() );
1503 TimeValue startCall
;
1504 osl_getSystemTime( &startCall
);
1506 int theRetVal
= ne_lock( m_pHttpSession
, theLock
);
1508 if ( theRetVal
== NE_OK
)
1510 m_aNeonLockStore
.addLock( theLock
,
1512 lastChanceToSendRefreshRequest(
1513 startCall
, theLock
->timeout
) );
1515 uno::Sequence
< rtl::OUString
> aTokens( 1 );
1516 aTokens
[ 0 ] = rtl::OUString::createFromAscii( theLock
->token
);
1517 rLock
.LockTokens
= aTokens
;
1519 OSL_TRACE( "NeonSession::LOCK: created lock for %s. token: %s",
1520 rtl::OUStringToOString( makeAbsoluteURL( inPath
),
1521 RTL_TEXTENCODING_UTF8
).getStr(),
1526 ne_lock_destroy( theLock
);
1528 OSL_TRACE( "NeonSession::LOCK: obtaining lock for %s failed!",
1529 rtl::OUStringToOString( makeAbsoluteURL( inPath
),
1530 RTL_TEXTENCODING_UTF8
).getStr() );
1533 HandleError( theRetVal
, inPath
, rEnv
);
1536 // -------------------------------------------------------------------
1537 // LOCK (refresh existing lock)
1538 // -------------------------------------------------------------------
1539 sal_Int64
NeonSession::LOCK( const ::rtl::OUString
& inPath
,
1541 const DAVRequestEnvironment
& rEnv
)
1542 throw ( DAVException
)
1544 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1546 // Try to get the neon lock from lock store
1548 = m_aNeonLockStore
.findByUri( makeAbsoluteURL( inPath
) );
1550 throw DAVException( DAVException::DAV_NOT_LOCKED
);
1554 // refresh existing lock.
1555 theLock
->timeout
= static_cast< long >( nTimeout
);
1557 TimeValue startCall
;
1558 osl_getSystemTime( &startCall
);
1560 int theRetVal
= ne_lock_refresh( m_pHttpSession
, theLock
);
1562 if ( theRetVal
== NE_OK
)
1564 m_aNeonLockStore
.updateLock( theLock
,
1565 lastChanceToSendRefreshRequest(
1566 startCall
, theLock
->timeout
) );
1569 HandleError( theRetVal
, inPath
, rEnv
);
1571 return theLock
->timeout
;
1574 // -------------------------------------------------------------------
1575 // LOCK (refresh existing lock)
1576 // -------------------------------------------------------------------
1577 bool NeonSession::LOCK( NeonLock
* pLock
,
1578 sal_Int32
& rlastChanceToSendRefreshRequest
)
1580 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1582 #if OSL_DEBUG_LEVEL > 0
1583 char * p
= ne_uri_unparse( &(pLock
->uri
) );
1584 OSL_TRACE( "NeonSession::LOCK: Refreshing lock for %s.", p
);
1588 // refresh existing lock.
1590 TimeValue startCall
;
1591 osl_getSystemTime( &startCall
);
1593 if ( ne_lock_refresh( m_pHttpSession
, pLock
) == NE_OK
)
1595 rlastChanceToSendRefreshRequest
1596 = lastChanceToSendRefreshRequest( startCall
, pLock
->timeout
);
1598 OSL_TRACE( "Lock successfully refreshed." );
1603 OSL_TRACE( "Lock not refreshed!" );
1608 // -------------------------------------------------------------------
1610 // -------------------------------------------------------------------
1611 void NeonSession::UNLOCK( const ::rtl::OUString
& inPath
,
1612 const DAVRequestEnvironment
& rEnv
)
1613 throw ( DAVException
)
1615 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1617 // get the neon lock from lock store
1619 = m_aNeonLockStore
.findByUri( makeAbsoluteURL( inPath
) );
1621 throw DAVException( DAVException::DAV_NOT_LOCKED
);
1625 int theRetVal
= ne_unlock( m_pHttpSession
, theLock
);
1627 if ( theRetVal
== NE_OK
)
1629 m_aNeonLockStore
.removeLock( theLock
);
1630 ne_lock_destroy( theLock
);
1634 OSL_TRACE( "NeonSession::UNLOCK: unlocking of %s failed.",
1635 rtl::OUStringToOString( makeAbsoluteURL( inPath
),
1636 RTL_TEXTENCODING_UTF8
).getStr() );
1639 HandleError( theRetVal
, inPath
, rEnv
);
1642 // -------------------------------------------------------------------
1644 // -------------------------------------------------------------------
1645 bool NeonSession::UNLOCK( NeonLock
* pLock
)
1647 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1649 #if OSL_DEBUG_LEVEL > 0
1650 char * p
= ne_uri_unparse( &(pLock
->uri
) );
1651 OSL_TRACE( "NeonSession::UNLOCK: Unlocking %s.", p
);
1655 if ( ne_unlock( m_pHttpSession
, pLock
) == NE_OK
)
1657 OSL_TRACE( "UNLOCK succeeded." );
1662 OSL_TRACE( "UNLOCK failed!" );
1667 // -------------------------------------------------------------------
1668 void NeonSession::abort()
1669 throw ( DAVException
)
1671 if ( m_pHttpSession
)
1673 osl::Guard
< osl::Mutex
> theGlobalGuard( aGlobalNeonMutex
);
1674 ne_close_connection( m_pHttpSession
);
1678 // -------------------------------------------------------------------
1679 const ucbhelper::InternetProxyServer
& NeonSession::getProxySettings() const
1681 if ( m_aScheme
== "http" || m_aScheme
== "https" )
1683 return m_rProxyDecider
.getProxy( m_aScheme
,
1689 return m_rProxyDecider
.getProxy( m_aScheme
,
1690 rtl::OUString() /* not used */,
1691 -1 /* not used */ );
1695 // -------------------------------------------------------------------
1698 bool containsLocktoken( const uno::Sequence
< ucb::Lock
> & rLocks
,
1699 const char * token
)
1701 for ( sal_Int32 n
= 0; n
< rLocks
.getLength(); ++n
)
1703 const uno::Sequence
< rtl::OUString
> & rTokens
1704 = rLocks
[ n
].LockTokens
;
1705 for ( sal_Int32 m
= 0; m
< rTokens
.getLength(); ++m
)
1707 if ( rTokens
[ m
].equalsAscii( token
) )
1716 // -------------------------------------------------------------------
1717 bool NeonSession::removeExpiredLocktoken( const rtl::OUString
& inURL
,
1718 const DAVRequestEnvironment
& rEnv
)
1720 NeonLock
* theLock
= m_aNeonLockStore
.findByUri( inURL
);
1724 // do a lockdiscovery to check whether this lock is still valid.
1727 // @@@ Alternative: use ne_lock_discover() => less overhead
1729 std::vector
< DAVResource
> aResources
;
1730 std::vector
< rtl::OUString
> aPropNames
;
1731 aPropNames
.push_back( DAVProperties::LOCKDISCOVERY
);
1733 PROPFIND( rEnv
.m_aRequestURI
, DAVZERO
, aPropNames
, aResources
, rEnv
);
1735 if ( aResources
.empty() )
1738 std::vector
< DAVPropertyValue
>::const_iterator it
1739 = aResources
[ 0 ].properties
.begin();
1740 std::vector
< DAVPropertyValue
>::const_iterator end
1741 = aResources
[ 0 ].properties
.end();
1745 if ( (*it
).Name
.equals( DAVProperties::LOCKDISCOVERY
) )
1747 uno::Sequence
< ucb::Lock
> aLocks
;
1748 if ( !( (*it
).Value
>>= aLocks
) )
1751 if ( !containsLocktoken( aLocks
, theLock
->token
) )
1763 // No lockdiscovery prop in propfind result / locktoken not found
1764 // in propfind result -> not locked
1765 OSL_TRACE( "NeonSession::removeExpiredLocktoken: Removing "
1766 " expired lock token for %s. token: %s",
1767 rtl::OUStringToOString( inURL
,
1768 RTL_TEXTENCODING_UTF8
).getStr(),
1771 m_aNeonLockStore
.removeLock( theLock
);
1772 ne_lock_destroy( theLock
);
1775 catch ( DAVException
const & )
1781 // -------------------------------------------------------------------
1783 // Common Error Handler
1784 // -------------------------------------------------------------------
1785 void NeonSession::HandleError( int nError
,
1786 const rtl::OUString
& inPath
,
1787 const DAVRequestEnvironment
& rEnv
)
1788 throw ( DAVException
)
1790 m_aEnv
= DAVRequestEnvironment();
1792 // Map error code to DAVException.
1798 case NE_ERROR
: // Generic error
1800 rtl::OUString aText
= rtl::OUString::createFromAscii(
1801 ne_get_error( m_pHttpSession
) );
1803 sal_uInt16 code
= makeStatusCode( aText
);
1805 if ( code
== SC_LOCKED
)
1807 if ( m_aNeonLockStore
.findByUri(
1808 makeAbsoluteURL( inPath
) ) == 0 )
1810 // locked by 3rd party
1811 throw DAVException( DAVException::DAV_LOCKED
);
1815 // locked by ourself
1816 throw DAVException( DAVException::DAV_LOCKED_SELF
);
1820 // Special handling for 400 and 412 status codes, which may indicate
1821 // that a lock previously obtained by us has been released meanwhile
1822 // by the server. Unfortunately, RFC is not clear at this point,
1823 // thus server implementations behave different...
1824 else if ( code
== SC_BAD_REQUEST
|| code
== SC_PRECONDITION_FAILED
)
1826 if ( removeExpiredLocktoken( makeAbsoluteURL( inPath
), rEnv
) )
1827 throw DAVException( DAVException::DAV_LOCK_EXPIRED
);
1830 throw DAVException( DAVException::DAV_HTTP_ERROR
, aText
, code
);
1832 case NE_LOOKUP
: // Name lookup failed.
1833 throw DAVException( DAVException::DAV_HTTP_LOOKUP
,
1834 NeonUri::makeConnectionEndPointString(
1835 m_aHostName
, m_nPort
) );
1837 case NE_AUTH
: // User authentication failed on server
1838 throw DAVException( DAVException::DAV_HTTP_AUTH
,
1839 NeonUri::makeConnectionEndPointString(
1840 m_aHostName
, m_nPort
) );
1842 case NE_PROXYAUTH
: // User authentication failed on proxy
1843 throw DAVException( DAVException::DAV_HTTP_AUTHPROXY
,
1844 NeonUri::makeConnectionEndPointString(
1845 m_aProxyName
, m_nProxyPort
) );
1847 case NE_CONNECT
: // Could not connect to server
1848 throw DAVException( DAVException::DAV_HTTP_CONNECT
,
1849 NeonUri::makeConnectionEndPointString(
1850 m_aHostName
, m_nPort
) );
1852 case NE_TIMEOUT
: // Connection timed out
1853 throw DAVException( DAVException::DAV_HTTP_TIMEOUT
,
1854 NeonUri::makeConnectionEndPointString(
1855 m_aHostName
, m_nPort
) );
1857 case NE_FAILED
: // The precondition failed
1858 throw DAVException( DAVException::DAV_HTTP_FAILED
,
1859 NeonUri::makeConnectionEndPointString(
1860 m_aHostName
, m_nPort
) );
1862 case NE_RETRY
: // Retry request (ne_end_request ONLY)
1863 throw DAVException( DAVException::DAV_HTTP_RETRY
,
1864 NeonUri::makeConnectionEndPointString(
1865 m_aHostName
, m_nPort
) );
1869 NeonUri
aUri( ne_redirect_location( m_pHttpSession
) );
1871 DAVException::DAV_HTTP_REDIRECT
, aUri
.GetURI() );
1875 OSL_TRACE( "NeonSession::HandleError : Unknown Neon error code!" );
1876 throw DAVException( DAVException::DAV_HTTP_ERROR
,
1877 rtl::OUString::createFromAscii(
1878 ne_get_error( m_pHttpSession
) ) );
1883 // -------------------------------------------------------------------
1886 void runResponseHeaderHandler( void * userdata
,
1887 const char * value
)
1889 rtl::OUString
aHeader( rtl::OUString::createFromAscii( value
) );
1890 sal_Int32 nPos
= aHeader
.indexOf( ':' );
1894 rtl::OUString
aHeaderName( aHeader
.copy( 0, nPos
) );
1896 NeonRequestContext
* pCtx
1897 = static_cast< NeonRequestContext
* >( userdata
);
1899 // Note: Empty vector means that all headers are requested.
1900 bool bIncludeIt
= ( pCtx
->pHeaderNames
->empty() );
1904 // Check whether this header was requested.
1905 std::vector
< ::rtl::OUString
>::const_iterator
it(
1906 pCtx
->pHeaderNames
->begin() );
1907 const std::vector
< ::rtl::OUString
>::const_iterator
end(
1908 pCtx
->pHeaderNames
->end() );
1912 // header names are case insensitive
1913 if ( (*it
).equalsIgnoreAsciiCase( aHeaderName
) )
1915 aHeaderName
= (*it
);
1927 // Create & set the PropertyValue
1928 DAVPropertyValue thePropertyValue
;
1929 thePropertyValue
.IsCaseSensitive
= false;
1930 thePropertyValue
.Name
= aHeaderName
;
1932 if ( nPos
< aHeader
.getLength() )
1933 thePropertyValue
.Value
<<= aHeader
.copy( nPos
+ 1 ).trim();
1935 // Add the newly created PropertyValue
1936 pCtx
->pResource
->properties
.push_back( thePropertyValue
);
1943 // -------------------------------------------------------------------
1945 int NeonSession::GET( ne_session
* sess
,
1947 ne_block_reader reader
,
1951 //struct get_context ctx;
1952 ne_request
* req
= ne_request_create( sess
, "GET", uri
);
1956 = ne_decompress_reader( req
, ne_accept_2xx
, reader
, userdata
);
1959 osl::Guard
< osl::Mutex
> theGlobalGuard( aGlobalNeonMutex
);
1960 ret
= ne_request_dispatch( req
);
1965 void *cursor
= NULL
;
1966 const char *name
, *value
;
1967 while ( ( cursor
= ne_response_header_iterate(
1968 req
, cursor
, &name
, &value
) ) != NULL
)
1972 ne_snprintf(buffer
, sizeof buffer
, "%s: %s", name
, value
);
1973 runResponseHeaderHandler(userdata
, buffer
);
1977 if ( ret
== NE_OK
&& ne_get_status( req
)->klass
!= 2 )
1981 ne_decompress_destroy(dc
);
1983 ne_request_destroy( req
);
1987 // -------------------------------------------------------------------
1989 int NeonSession::PUT( ne_session
* sess
,
1991 const char * buffer
,
1994 ne_request
* req
= ne_request_create( sess
, "PUT", uri
);
1997 ne_lock_using_resource( req
, uri
, 0 );
1998 ne_lock_using_parent( req
, uri
);
2000 ne_set_request_body_buffer( req
, buffer
, size
);
2003 osl::Guard
< osl::Mutex
> theGlobalGuard( aGlobalNeonMutex
);
2004 ret
= ne_request_dispatch( req
);
2007 if ( ret
== NE_OK
&& ne_get_status( req
)->klass
!= 2 )
2010 ne_request_destroy( req
);
2014 // -------------------------------------------------------------------
2015 int NeonSession::POST( ne_session
* sess
,
2017 const char * buffer
,
2018 ne_block_reader reader
,
2020 const rtl::OUString
& rContentType
,
2021 const rtl::OUString
& rReferer
)
2023 ne_request
* req
= ne_request_create( sess
, "POST", uri
);
2024 //struct get_context ctx;
2027 RequestDataMap
* pData
= 0;
2029 if ( !rContentType
.isEmpty() || !rReferer
.isEmpty() )
2031 // Remember contenttype and referer. Data will be added to HTTP request
2032 // header in in 'PreSendRequest' callback.
2033 pData
= static_cast< RequestDataMap
* >( m_pRequestData
);
2034 (*pData
)[ req
] = RequestData( rContentType
, rReferer
);
2040 //ctx.session = sess;
2042 ///* Read the value of the Content-Length header into ctx.total */
2043 //ne_add_response_header_handler( req, "Content-Length",
2044 // ne_handle_numeric_header, &ctx.total );
2046 ne_add_response_body_reader( req
, ne_accept_2xx
, reader
, userdata
);
2048 ne_set_request_body_buffer( req
, buffer
, strlen( buffer
) );
2051 osl::Guard
< osl::Mutex
> theGlobalGuard( aGlobalNeonMutex
);
2052 ret
= ne_request_dispatch( req
);
2058 if ( ret
== NE_OK
&& ne_get_status( req
)->klass
!= 2 )
2061 ne_request_destroy( req
);
2065 // Remove request data from session's list.
2066 RequestDataMap::iterator it
= pData
->find( req
);
2067 if ( it
!= pData
->end() )
2074 // -------------------------------------------------------------------
2077 NeonSession::getDataFromInputStream(
2078 const uno::Reference
< io::XInputStream
> & xStream
,
2079 uno::Sequence
< sal_Int8
> & rData
,
2080 bool bAppendTrailingZeroByte
)
2084 uno::Reference
< io::XSeekable
> xSeekable( xStream
, uno::UNO_QUERY
);
2085 if ( xSeekable
.is() )
2090 = sal::static_int_cast
<sal_Int32
>(xSeekable
->getLength());
2092 = xStream
->readBytes( rData
, nSize
);
2094 if ( nRead
== nSize
)
2096 if ( bAppendTrailingZeroByte
)
2098 rData
.realloc( nSize
+ 1 );
2099 rData
[ nSize
] = sal_Int8( 0 );
2104 catch ( io::NotConnectedException
const & )
2108 catch ( io::BufferSizeExceededException
const & )
2112 catch ( io::IOException
const & )
2114 // getLength, readBytes
2121 uno::Sequence
< sal_Int8
> aBuffer
;
2124 sal_Int32 nRead
= xStream
->readSomeBytes( aBuffer
, 65536 );
2127 if ( rData
.getLength() < ( nPos
+ nRead
) )
2128 rData
.realloc( nPos
+ nRead
);
2130 aBuffer
.realloc( nRead
);
2131 rtl_copyMemory( (void*)( rData
.getArray() + nPos
),
2132 (const void*)aBuffer
.getConstArray(),
2136 aBuffer
.realloc( 0 );
2137 nRead
= xStream
->readSomeBytes( aBuffer
, 65536 );
2140 if ( bAppendTrailingZeroByte
)
2142 rData
.realloc( nPos
+ 1 );
2143 rData
[ nPos
] = sal_Int8( 0 );
2147 catch ( io::NotConnectedException
const & )
2151 catch ( io::BufferSizeExceededException
const & )
2155 catch ( io::IOException
const & )
2164 // ---------------------------------------------------------------------
2166 NeonSession::isDomainMatch( rtl::OUString certHostName
)
2168 rtl::OUString hostName
= getHostName();
2170 if (hostName
.equalsIgnoreAsciiCase( certHostName
) )
2173 if ( 0 == certHostName
.indexOf( rtl::OUString("*") ) &&
2174 hostName
.getLength() >= certHostName
.getLength() )
2176 rtl::OUString cmpStr
= certHostName
.copy( 1 );
2178 if ( hostName
.matchIgnoreAsciiCase(
2179 cmpStr
, hostName
.getLength() - cmpStr
.getLength() ) )
2185 // ---------------------------------------------------------------------
2186 rtl::OUString
NeonSession::makeAbsoluteURL( rtl::OUString
const & rURL
) const
2190 // Is URL relative or already absolute?
2191 if ( rURL
[ 0 ] != sal_Unicode( '/' ) )
2194 return rtl::OUString( rURL
);
2199 memset( &aUri
, 0, sizeof( aUri
) );
2201 ne_fill_server_uri( m_pHttpSession
, &aUri
);
2203 = ne_strdup( rtl::OUStringToOString(
2204 rURL
, RTL_TEXTENCODING_UTF8
).getStr() );
2205 NeonUri
aNeonUri( &aUri
);
2206 ne_uri_free( &aUri
);
2207 return aNeonUri
.GetURI();
2210 catch ( DAVException
const & )
2214 return rtl::OUString();
2217 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */