1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: NeonSession.cxx,v $
10 * $Revision: 1.55.12.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_ucb.hxx"
37 #include <rtl/string.h>
38 #include <ne_socket.h>
40 #include <ne_redirect.h>
43 #include "libxml/parser.h"
44 #include <rtl/ustrbuf.hxx>
45 #include "comphelper/sequence.hxx"
47 #include "DAVAuthListener.hxx"
48 #include "NeonTypes.hxx"
49 #include "NeonSession.hxx"
50 #include "NeonInputStream.hxx"
51 #include "NeonPropFindRequest.hxx"
52 #include "NeonHeadRequest.hxx"
53 #include "NeonUri.hxx"
54 #ifndef _LINKSEQUENCE_HXX_
55 #include "LinkSequence.hxx"
58 #include <com/sun/star/xml/crypto/XSEInitializer.hpp>
59 #include "UCBDeadPropertyValue.hxx"
60 #include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
61 #include <com/sun/star/security/XCertificate.hpp>
62 #include <com/sun/star/security/CertificateValidity.hpp>
63 #include <com/sun/star/security/CertificateContainerStatus.hpp>
64 #include <com/sun/star/security/CertificateContainer.hpp>
65 #include <com/sun/star/security/XCertificateContainer.hpp>
66 #include <com/sun/star/task/XMasterPasswordHandling.hpp>
69 #ifndef _SIMPLECERTIFICATIONVALIDATIONREQUEST_HXX_
70 #include "ucbhelper/simplecertificatevalidationrequest.hxx"
72 #include <ucbhelper/cancelcommandexecution.hxx>
74 #include <cppuhelper/bootstrap.hxx>
77 using namespace com::sun::star
;
78 using namespace webdav_ucp
;
79 using namespace com::sun::star::security
;
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 std::hash_map
132 // -------------------------------------------------------------------
134 bool NeonSession::m_bGlobalsInited
= false;
135 osl::Mutex
NeonSession::m_aGlobalMutex
;
136 // -------------------------------------------------------------------
138 // -------------------------------------------------------------------
139 static sal_uInt16
makeStatusCode( const rtl::OUString
& rStatusText
)
141 // Extract status code from session error string. Unfortunately
142 // neon provides no direct access to the status code...
144 if ( rStatusText
.getLength() < 3 )
147 sal_False
, "makeStatusCode - status text string to short!" );
151 sal_Int32 nPos
= rStatusText
.indexOf( ' ' );
154 OSL_ENSURE( sal_False
, "makeStatusCode - wrong status text format!" );
158 return sal_uInt16( rStatusText
.copy( 0, nPos
).toInt32() );
161 static sal_uInt16
getStatusCode( HttpSession
*pSession
)
163 rtl::OUString aText
= rtl::OUString::createFromAscii( ne_get_error( pSession
) );
164 return makeStatusCode( aText
);
167 // -------------------------------------------------------------------
168 struct NeonRequestContext
170 uno::Reference
< io::XOutputStream
> xOutputStream
;
171 rtl::Reference
< NeonInputStream
> xInputStream
;
172 const std::vector
< ::rtl::OUString
> * pHeaderNames
;
173 DAVResource
* pResource
;
175 NeonRequestContext( uno::Reference
< io::XOutputStream
> & xOutStrm
)
176 : xOutputStream( xOutStrm
), xInputStream( 0 ),
177 pHeaderNames( 0 ), pResource( 0 ) {}
179 NeonRequestContext( const rtl::Reference
< NeonInputStream
> & xInStrm
)
180 : xOutputStream( 0 ), xInputStream( xInStrm
),
181 pHeaderNames( 0 ), pResource( 0 ) {}
183 NeonRequestContext( uno::Reference
< io::XOutputStream
> & xOutStrm
,
184 const std::vector
< ::rtl::OUString
> & inHeaderNames
,
185 DAVResource
& ioResource
)
186 : xOutputStream( xOutStrm
), xInputStream( 0 ),
187 pHeaderNames( &inHeaderNames
), pResource( &ioResource
) {}
189 NeonRequestContext( const rtl::Reference
< NeonInputStream
> & xInStrm
,
190 const std::vector
< ::rtl::OUString
> & inHeaderNames
,
191 DAVResource
& ioResource
)
192 : xOutputStream( 0 ), xInputStream( xInStrm
),
193 pHeaderNames( &inHeaderNames
), pResource( &ioResource
) {}
196 //--------------------------------------------------------------------
197 //--------------------------------------------------------------------
199 // Callback functions
201 //--------------------------------------------------------------------
202 //--------------------------------------------------------------------
204 // -------------------------------------------------------------------
205 // ResponseBlockReader
206 // A simple Neon response_block_reader for use with an XInputStream
207 // -------------------------------------------------------------------
209 #if NEON_VERSION >= 0x0250
214 NeonSession_ResponseBlockReader( void * inUserData
,
218 // neon calls this function with (inLen == 0)...
221 NeonRequestContext
* pCtx
222 = static_cast< NeonRequestContext
* >( inUserData
);
224 rtl::Reference
< NeonInputStream
> xInputStream(
227 if ( xInputStream
.is() )
228 xInputStream
->AddToStream( inBuf
, inLen
);
230 #if NEON_VERSION >= 0x0250
235 // -------------------------------------------------------------------
236 // ResponseBlockWriter
237 // A simple Neon response_block_reader for use with an XOutputStream
238 // -------------------------------------------------------------------
240 #if NEON_VERSION >= 0x0250
245 NeonSession_ResponseBlockWriter( void * inUserData
,
249 // neon calls this function with (inLen == 0)...
252 NeonRequestContext
* pCtx
253 = static_cast< NeonRequestContext
* >( inUserData
);
254 uno::Reference
< io::XOutputStream
> xOutputStream
255 = pCtx
->xOutputStream
;
257 if ( xOutputStream
.is() )
259 const uno::Sequence
< sal_Int8
> aSeq( (sal_Int8
*)inBuf
, inLen
);
260 xOutputStream
->writeBytes( aSeq
);
263 #if NEON_VERSION >= 0x0250
268 // -------------------------------------------------------------------
269 extern "C" int NeonSession_NeonAuth( void * inUserData
,
270 const char * inRealm
,
272 char * inoutUserName
,
273 char * inoutPassWord
)
275 /* The callback used to request the username and password in the given
276 * realm. The username and password must be copied into the buffers
277 * which are both of size NE_ABUFSIZ. The 'attempt' parameter is zero
278 * on the first call to the callback, and increases by one each time
279 * an attempt to authenticate fails.
281 * The callback must return zero to indicate that authentication
282 * should be attempted with the username/password, or non-zero to
283 * cancel the request. (if non-zero, username and password are
289 // Give'em only a limited mumber of retries..
297 NeonSession
* theSession
= static_cast< NeonSession
* >( inUserData
);
298 DAVAuthListener
* pListener
299 = theSession
->getRequestEnvironment().m_xAuthListener
.get();
305 rtl::OUString theUserName
;
306 rtl::OUString thePassWord
;
310 // neon does not handle username supplied with request URI (for
311 // instance when doing FTP over proxy - last checked: 0.23.5 )
315 rtl::OUString
aUserInfo( theSession
->getUserInfo() );
316 if ( aUserInfo
.getLength() )
318 sal_Int32 nPos
= aUserInfo
.indexOf( ':' );
321 theUserName
= aUserInfo
;
325 theUserName
= aUserInfo
.copy( 0, nPos
);
326 thePassWord
= aUserInfo
.copy( nPos
+ 1 );
330 catch ( DAVException
const & )
338 // username buffer is prefilled with user name from last attempt.
339 theUserName
= rtl::OUString::createFromAscii( inoutUserName
);
340 // @@@ Neon does not initialize password buffer (last checked: 0.22.0).
341 //thePassWord = rtl::OUString::createFromAscii( inoutPassWord );
344 //i97003 (tkr): Ask XMasterPasswordHandling if we should store the credentials persistently and give this information to the SimpleAuthenticationRequest
345 uno::Reference
< ::com::sun::star::task::XMasterPasswordHandling
> xMasterPasswordHandling
=
346 uno::Reference
< ::com::sun::star::task::XMasterPasswordHandling
>(
347 theSession
->getMSF().get()->createInstance( rtl::OUString::createFromAscii( "com.sun.star.task.PasswordContainer" )), uno::UNO_QUERY
);
350 int theRetVal
= pListener
->authenticate(
351 rtl::OUString::createFromAscii( inRealm
),
352 theSession
->getHostName(),
355 xMasterPasswordHandling
.is() ? xMasterPasswordHandling
->isPersistentStoringAllowed() : sal_False
);
358 rtl::OUStringToOString( theUserName
, RTL_TEXTENCODING_UTF8
) );
359 if ( aUser
.getLength() > ( NE_ABUFSIZ
- 1 ) )
362 sal_False
, "NeonSession_NeonAuth - username to long!" );
367 rtl::OUStringToOString( thePassWord
, RTL_TEXTENCODING_UTF8
) );
368 if ( aPass
.getLength() > ( NE_ABUFSIZ
- 1 ) )
371 sal_False
, "NeonSession_NeonAuth - password to long!" );
375 strcpy( inoutUserName
, // #100211# - checked
376 rtl::OUStringToOString( theUserName
, RTL_TEXTENCODING_UTF8
) );
378 strcpy( inoutPassWord
, // #100211# - checked
379 rtl::OUStringToOString( thePassWord
, RTL_TEXTENCODING_UTF8
) );
385 // -------------------------------------------------------------------
388 // -------------------------------------------------------------------
390 ::rtl::OUString
GetHostnamePart( const ::rtl::OUString
& _rRawString
)
392 ::rtl::OUString sPart
;
393 ::rtl::OUString sPartId
= ::rtl::OUString::createFromAscii( "CN=" );
394 sal_Int32 nContStart
= _rRawString
.indexOf( sPartId
);
395 if ( nContStart
!= -1 )
397 nContStart
= nContStart
+ sPartId
.getLength();
398 sal_Int32 nContEnd
= _rRawString
.indexOf( sal_Unicode( ',' ), nContStart
);
399 sPart
= _rRawString
.copy( nContStart
, nContEnd
- nContStart
);
404 // -------------------------------------------------------------------
405 extern "C" int NeonSession_CertificationNotify( void *userdata
,
407 const ne_ssl_certificate
*cert
)
410 NeonSession
* pSession
= static_cast< NeonSession
* >( userdata
);
411 uno::Reference
< ::com::sun::star::xml::crypto::XSecurityEnvironment
> xSecurityEnv
;
412 uno::Reference
< ::com::sun::star::security::XCertificateContainer
> xCertificateContainer
;
415 xCertificateContainer
= uno::Reference
< ::com::sun::star::security::XCertificateContainer
>(
416 pSession
->getMSF().get()->createInstance( rtl::OUString::createFromAscii( "com.sun.star.security.CertificateContainer" )), uno::UNO_QUERY
);
418 // YD if xmlsecurity is not built (os2), we cannot continue.
419 if (!xCertificateContainer
.is())
426 dn
= ne_ssl_readable_dname( ne_ssl_cert_subject( cert
) );
428 rtl::OUString
cert_subject( dn
, strlen( dn
), RTL_TEXTENCODING_UTF8
, 0 );
432 CertificateContainerStatus certificateContainer
;
433 certificateContainer
= xCertificateContainer
.get()->hasCertificate( pSession
->getHostName(), cert_subject
);
435 if( certificateContainer
!= CertificateContainerStatus_NOCERT
)
437 if( certificateContainer
== CertificateContainerStatus_TRUSTED
)
443 rtl::OUString sSEInitializer
;
444 ::com::sun::star::uno::Reference
< com::sun::star::xml::crypto::XSEInitializer
> mxSEInitializer
;
445 ::com::sun::star::uno::Reference
< com::sun::star::xml::crypto::XXMLSecurityContext
> mxSecurityContext
;
447 sSEInitializer
= rtl::OUString::createFromAscii( SEINITIALIZER_COMPONENT
);
448 mxSEInitializer
= uno::Reference
< com::sun::star::xml::crypto::XSEInitializer
> (
449 pSession
->getMSF().get()->createInstance( sSEInitializer
), uno::UNO_QUERY
);
451 if ( mxSEInitializer
.is() )
452 mxSecurityContext
= mxSEInitializer
->createSecurityContext( rtl::OUString::createFromAscii( "" ) );
454 xSecurityEnv
= mxSecurityContext
->getSecurityEnvironment();
457 //The end entity certificate
458 char * eeCertB64
= ne_ssl_cert_export( cert
);
460 ::rtl::OString
sEECertB64( eeCertB64
);
462 uno::Reference
< com::sun::star::security::XCertificate
> xEECert
=
463 xSecurityEnv
->createCertificateFromAscii(
464 ::rtl::OStringToOUString( sEECertB64
, RTL_TEXTENCODING_ASCII_US
) );
469 std::vector
<uno::Reference
<com::sun::star::security::XCertificate
> > vecCerts
;
470 const ne_ssl_certificate
* issuerCert
= cert
;
473 //get the intermediate certificate
474 //the returned value is const ! Therfore it does not need to be freed
475 //with ne_ssl_cert_free, which takes a non-const argument
476 issuerCert
= ne_ssl_cert_signedby(issuerCert
);
477 if (NULL
== issuerCert
)
480 char * imCertB64
= ne_ssl_cert_export(issuerCert
);
481 ::rtl::OString
sInterMediateCertB64(imCertB64
);
483 uno::Reference
< com::sun::star::security::XCertificate
> xImCert
=
484 xSecurityEnv
->createCertificateFromAscii(
485 ::rtl::OStringToOUString( sInterMediateCertB64
, RTL_TEXTENCODING_ASCII_US
) );
487 vecCerts
.push_back(xImCert
);
490 sal_Int64 certValidity
= xSecurityEnv
->verifyCertificate( xEECert
,
491 ::comphelper::containerToSequence(vecCerts
) );
494 if ( pSession
->isDomainMatch( GetHostnamePart( xEECert
.get()->getSubjectName())) )
496 //if host name matched with certificate then look if the certificate was ok
497 if( certValidity
== ::security::CertificateValidity::VALID
)
501 const uno::Reference
< ucb::XCommandEnvironment
> xEnv
=
502 pSession
->getRequestEnvironment().m_xEnv
.get();
506 failures
= static_cast<int>(certValidity
);
508 uno::Reference
< task::XInteractionHandler
> xIH
509 = xEnv
->getInteractionHandler();
512 rtl::Reference
< ucbhelper::SimpleCertificateValidationRequest
> xRequest
513 = new ucbhelper::SimpleCertificateValidationRequest((sal_Int32
)failures
, xEECert
, pSession
->getHostName() );
514 xIH
->handle( xRequest
.get() );
516 rtl::Reference
< ucbhelper::InteractionContinuation
> xSelection
517 = xRequest
->getSelection();
519 if ( xSelection
.is() )
521 uno::Reference
< task::XInteractionApprove
> xApprove(
522 xSelection
.get(), uno::UNO_QUERY
);
525 xCertificateContainer
->addCertificate(pSession
->getHostName(), cert_subject
, sal_True
);
529 xCertificateContainer
->addCertificate(pSession
->getHostName(), cert_subject
, sal_False
);
537 xCertificateContainer
->addCertificate(pSession
->getHostName(), cert_subject
, sal_False
);
546 // -------------------------------------------------------------------
547 extern "C" void NeonSession_PreSendRequest( ne_request
* req
,
549 ne_buffer
* headers
)
551 // userdata -> value returned by 'create'
553 NeonSession
* pSession
= static_cast< NeonSession
* >( userdata
);
556 // If there is a proxy server in between, it shall never use
557 // cached data. We always want 'up-to-date' data.
558 ne_buffer_concat( headers
, "Pragma: no-cache", EOL
, NULL
);
559 // alternative, but understoud by HTTP 1.1 servers only:
560 // ne_buffer_concat( headers, "Cache-Control: max-age=0", EOL, NULL );
562 const RequestDataMap
* pRequestData
563 = static_cast< const RequestDataMap
* >(
564 pSession
->getRequestData() );
566 RequestDataMap::const_iterator it
= pRequestData
->find( req
);
567 if ( it
!= pRequestData
->end() )
569 if ( (*it
).second
.aContentType
.getLength() )
571 char * pData
= headers
->data
;
572 if ( strstr( pData
, "Content-Type:" ) == NULL
)
575 = rtl::OUStringToOString( (*it
).second
.aContentType
,
576 RTL_TEXTENCODING_UTF8
);
577 ne_buffer_concat( headers
, "Content-Type: ",
578 aType
.getStr(), EOL
, NULL
);
582 if ( (*it
).second
.aReferer
.getLength() )
584 char * pData
= headers
->data
;
585 if ( strstr( pData
, "Referer:" ) == NULL
)
587 rtl::OString aReferer
588 = rtl::OUStringToOString( (*it
).second
.aReferer
,
589 RTL_TEXTENCODING_UTF8
);
590 ne_buffer_concat( headers
, "Referer: ",
591 aReferer
.getStr(), EOL
, NULL
);
596 const DAVRequestHeaders
& rHeaders
597 = pSession
->getRequestEnvironment().m_aRequestHeaders
;
599 DAVRequestHeaders::const_iterator
it1( rHeaders
.begin() );
600 const DAVRequestHeaders::const_iterator
end1( rHeaders
.end() );
602 while ( it1
!= end1
)
605 = rtl::OUStringToOString( (*it1
).first
,
606 RTL_TEXTENCODING_UTF8
);
608 = rtl::OUStringToOString( (*it1
).second
,
609 RTL_TEXTENCODING_UTF8
);
610 ne_buffer_concat( headers
, aHeader
.getStr(), ": ",
611 aValue
.getStr(), EOL
, NULL
);
618 NeonLockStore
* NeonSession::s_aNeonLockStore
= NULL
;
620 // -------------------------------------------------------------------
622 // -------------------------------------------------------------------
623 NeonSession::NeonSession(
624 const rtl::Reference
< DAVSessionFactory
> & rSessionFactory
,
625 const rtl::OUString
& inUri
,
626 const ucbhelper::InternetProxyDecider
& rProxyDecider
)
627 throw ( DAVException
)
628 : DAVSession( rSessionFactory
),
630 m_pRequestData( new RequestDataMap
),
631 m_rProxyDecider( rProxyDecider
)
633 NeonUri
theUri( inUri
);
634 m_aScheme
= theUri
.GetScheme();
635 m_aHostName
= theUri
.GetHost();
636 m_nPort
= theUri
.GetPort();
637 m_aUserInfo
= theUri
.GetUserInfo();
642 // -------------------------------------------------------------------
644 // -------------------------------------------------------------------
645 NeonSession::~NeonSession( )
647 if ( m_pHttpSession
)
649 ne_session_destroy( m_pHttpSession
);
653 delete static_cast<RequestDataMap
*>(m_pRequestData
);
656 // -------------------------------------------------------------------
657 void NeonSession::Init()
658 throw ( DAVException
)
660 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
662 bool bCreateNewSession
= false;
664 if ( m_pHttpSession
== 0 )
666 // Ensure that Neon sockets are initialize
668 // --> tkr #151111# crashed if copy and pasted pictures from the internet
669 // ne_sock_init() was executed by two threads at the same time.
670 osl::Guard
< osl::Mutex
> theGlobalGuard( m_aGlobalMutex
);
672 if ( !m_bGlobalsInited
)
674 if ( ne_sock_init() != 0 )
675 throw DAVException( DAVException::DAV_SESSION_CREATE
,
676 NeonUri::makeConnectionEndPointString(
677 m_aHostName
, m_nPort
) );
678 #if OSL_DEBUG_LEVEL > 0
679 ne_debug_init( stderr
, NE_DBG_LOCKS
);
681 // #122205# - libxml2 needs to be initialized once if used by
682 // multithreaded programs like OOo.
684 m_bGlobalsInited
= true;
687 const ucbhelper::InternetProxyServer
& rProxyCfg
= getProxySettings();
689 m_aProxyName
= rProxyCfg
.aName
;
690 m_nProxyPort
= rProxyCfg
.nPort
;
692 // Not yet initialized. Create new session.
693 bCreateNewSession
= true;
697 // #112271# Check whether proxy settings are still valid (They may
698 // change at any time). If not, create new Neon session.
700 const ucbhelper::InternetProxyServer
& rProxyCfg
= getProxySettings();
702 if ( ( rProxyCfg
.aName
!= m_aProxyName
)
703 || ( rProxyCfg
.nPort
!= m_nProxyPort
) )
705 m_aProxyName
= rProxyCfg
.aName
;
706 m_nProxyPort
= rProxyCfg
.nPort
;
708 // new session needed, destroy old first
709 ne_session_destroy( m_pHttpSession
);
711 bCreateNewSession
= true;
715 if ( bCreateNewSession
)
717 // @@@ For FTP over HTTP proxy inUserInfo is needed to be able to
718 // build the complete request URI (including user:pass), but
719 // currently (0.22.0) neon does not allow to pass the user info
722 m_pHttpSession
= ne_session_create(
723 rtl::OUStringToOString( m_aScheme
,
724 RTL_TEXTENCODING_UTF8
).getStr(),
725 /* theUri.GetUserInfo(),
726 @@@ for FTP via HTTP proxy, but not supported by Neon */
727 rtl::OUStringToOString( m_aHostName
,
728 RTL_TEXTENCODING_UTF8
).getStr(),
731 if ( m_pHttpSession
== 0 )
732 throw DAVException( DAVException::DAV_SESSION_CREATE
,
733 NeonUri::makeConnectionEndPointString(
734 m_aHostName
, m_nPort
) );
736 if (m_aScheme
.equalsIgnoreAsciiCase( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
740 // Get all trusted certificates from key store
744 // Set a failure callback for certificate check
745 ne_ssl_set_verify( m_pHttpSession
, NeonSession_CertificationNotify
, this);
748 // Add hooks (i.e. for adding additional headers to the request)
751 /* Hook called when a request is created. */
752 //typedef void (*ne_create_request_fn)(ne_request *req, void *userdata,
753 // const char *method, const char *path);
755 ne_hook_create_request( m_pHttpSession
, create_req_hook_fn
, this );
758 /* Hook called before the request is sent. 'header' is the raw HTTP
759 * header before the trailing CRLF is added: add in more here. */
760 //typedef void (*ne_pre_send_fn)(ne_request *req, void *userdata,
761 // ne_buffer *header);
763 ne_hook_pre_send( m_pHttpSession
, NeonSession_PreSendRequest
, this );
766 /* Hook called after the request is sent. May return:
767 * NE_OK everything is okay
768 * NE_RETRY try sending the request again.
769 * anything else signifies an error, and the request is failed. The
770 * return code is passed back the _dispatch caller, so the session error
771 * must also be set appropriately (ne_set_error).
773 //typedef int (*ne_post_send_fn)(ne_request *req, void *userdata,
774 // const ne_status *status);
776 ne_hook_post_send( m_pHttpSession
, post_send_req_hook_fn
, this );
778 /* Hook called when the request is destroyed. */
779 //typedef void (*ne_destroy_req_fn)(ne_request *req, void *userdata);
781 ne_hook_destroy_request( m_pHttpSession
, destroy_req_hook_fn
, this );
783 /* Hook called when the session is destroyed. */
784 //typedef void (*ne_destroy_sess_fn)(void *userdata);
786 ne_hook_destroy_session( m_pHttpSession
, destroy_sess_hook_fn
, this );
789 if ( m_aProxyName
.getLength() )
791 ne_session_proxy( m_pHttpSession
,
792 rtl::OUStringToOString( m_aProxyName
,
793 RTL_TEXTENCODING_UTF8
)
798 if ( !s_aNeonLockStore
)
799 s_aNeonLockStore
= ne_lockstore_create();
801 if ( s_aNeonLockStore
== NULL
)
802 throw DAVException( DAVException::DAV_SESSION_CREATE
,
803 NeonUri::makeConnectionEndPointString( m_aHostName
, m_nPort
) );
805 // Register the lock store
806 ne_lockstore_register( s_aNeonLockStore
, m_pHttpSession
);
808 // Register for redirects.
809 ne_redirect_register( m_pHttpSession
);
811 // authentication callbacks.
813 // Note: Calling ne_set_[server|proxy]_auth more than once per
814 // m_pHttpSession instance sometimes(?) crashes Neon! ( last
816 #if NEON_VERSION >= 0x0260
817 ne_add_server_auth( m_pHttpSession
, NE_AUTH_ALL
, NeonSession_NeonAuth
, this );
818 ne_add_proxy_auth ( m_pHttpSession
, NE_AUTH_ALL
, NeonSession_NeonAuth
, this );
820 ne_set_server_auth( m_pHttpSession
, NeonSession_NeonAuth
, this );
821 ne_set_proxy_auth ( m_pHttpSession
, NeonSession_NeonAuth
, this );
826 // -------------------------------------------------------------------
828 sal_Bool
NeonSession::CanUse( const rtl::OUString
& inUri
)
832 NeonUri
theUri( inUri
);
833 if ( ( theUri
.GetPort() == m_nPort
) &&
834 ( theUri
.GetHost() == m_aHostName
) &&
835 ( theUri
.GetScheme() == m_aScheme
) )
838 catch ( DAVException
const & )
845 // -------------------------------------------------------------------
847 sal_Bool
NeonSession::UsesProxy()
850 return ( m_aProxyName
.getLength() > 0 );
853 // -------------------------------------------------------------------
855 // -------------------------------------------------------------------
856 void NeonSession::OPTIONS( const rtl::OUString
& inPath
,
857 DAVCapabilities
& outCapabilities
,
858 const DAVRequestEnvironment
& rEnv
)
859 throw( DAVException
)
861 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
867 HttpServerCapabilities servercaps
;
868 memset( &servercaps
, 0, sizeof( servercaps
) );
870 int theRetVal
= ne_options( m_pHttpSession
,
871 rtl::OUStringToOString(
872 inPath
, RTL_TEXTENCODING_UTF8
),
874 HandleError( theRetVal
);
876 outCapabilities
.class1
= !!servercaps
.dav_class1
;
877 outCapabilities
.class2
= !!servercaps
.dav_class2
;
878 outCapabilities
.executable
= !!servercaps
.dav_executable
;
881 // -------------------------------------------------------------------
882 // PROPFIND - allprop & named
883 // -------------------------------------------------------------------
884 void NeonSession::PROPFIND( const rtl::OUString
& inPath
,
886 const std::vector
< rtl::OUString
> & inPropNames
,
887 std::vector
< DAVResource
> & ioResources
,
888 const DAVRequestEnvironment
& rEnv
)
889 throw ( DAVException
)
891 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
897 int theRetVal
= NE_OK
;
898 NeonPropFindRequest
theRequest( m_pHttpSession
,
899 rtl::OUStringToOString(
900 inPath
, RTL_TEXTENCODING_UTF8
),
905 HandleError( theRetVal
);
908 // -------------------------------------------------------------------
909 // PROPFIND - propnames
910 // -------------------------------------------------------------------
911 void NeonSession::PROPFIND( const rtl::OUString
& inPath
,
913 std::vector
< DAVResourceInfo
>& ioResInfo
,
914 const DAVRequestEnvironment
& rEnv
)
915 throw( DAVException
)
917 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
923 int theRetVal
= NE_OK
;
924 NeonPropFindRequest
theRequest( m_pHttpSession
,
925 rtl::OUStringToOString(
926 inPath
, RTL_TEXTENCODING_UTF8
),
930 HandleError( theRetVal
);
933 // -------------------------------------------------------------------
935 // -------------------------------------------------------------------
936 void NeonSession::PROPPATCH( const rtl::OUString
& inPath
,
937 const std::vector
< ProppatchValue
> & inValues
,
938 const DAVRequestEnvironment
& rEnv
)
939 throw( DAVException
)
941 /* @@@ Which standard live properties can be set by the client?
942 This is a known WebDAV RFC issue ( verified: 04/10/2001 )
943 --> http://www.ics.uci.edu/pub/ietf/webdav/protocol/issues.html
945 mod_dav implementation:
947 creationdate r ( File System prop )
949 getcontentlanguage r ( #ifdef DAV_DISABLE_WRITEABLE_PROPS )
950 getcontentlength r ( File System prop )
951 getcontenttype r ( #ifdef DAV_DISABLE_WRITEABLE_PROPS )
952 getetag r ( File System prop )
953 getlastmodified r ( File System prop )
958 executable w ( #ifndef WIN32 )
960 All dead properties are of course writable.
963 int theRetVal
= NE_OK
;
964 int n
; // for the "for" loop
966 // Generate the list of properties we want to set.
967 int nPropCount
= inValues
.size();
968 ne_proppatch_operation
* pItems
969 = new ne_proppatch_operation
[ nPropCount
+ 1 ];
970 for ( n
= 0; n
< nPropCount
; ++n
)
972 const ProppatchValue
& rValue
= inValues
[ n
];
974 // Split fullname into namespace and name!
975 ne_propname
* pName
= new ne_propname
;
976 DAVProperties::createNeonPropName( rValue
.name
, *pName
);
977 pItems
[ n
].name
= pName
;
979 if ( rValue
.operation
== PROPSET
)
981 pItems
[ n
].type
= ne_propset
;
983 rtl::OUString aStringValue
;
984 if ( DAVProperties::isUCBDeadProperty( *pName
) )
986 // DAV dead property added by WebDAV UCP?
987 if ( !UCBDeadPropertyValue::toXML(
988 rValue
.value
, aStringValue
) )
991 pItems
[ n
].value
= 0;
992 theRetVal
= NE_ERROR
;
997 else if ( !( rValue
.value
>>= aStringValue
) )
999 // complex properties...
1000 if ( rValue
.name
== DAVProperties::SOURCE
)
1002 uno::Sequence
< ::com::sun::star::ucb::Link
> aLinks
;
1003 if ( rValue
.value
>>= aLinks
)
1005 LinkSequence::toXML( aLinks
, aStringValue
);
1010 pItems
[ n
].value
= 0;
1011 theRetVal
= NE_ERROR
;
1018 OSL_ENSURE( sal_False
,
1019 "NeonSession::PROPPATCH - unsupported type!" );
1021 pItems
[ n
].value
= 0;
1022 theRetVal
= NE_ERROR
;
1028 = strdup( rtl::OUStringToOString( aStringValue
,
1029 RTL_TEXTENCODING_UTF8
) );
1033 pItems
[ n
].type
= ne_propremove
;
1034 pItems
[ n
].value
= 0;
1038 if ( theRetVal
== NE_OK
)
1040 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1046 pItems
[ n
].name
= 0;
1048 theRetVal
= ne_proppatch( m_pHttpSession
,
1049 rtl::OUStringToOString(
1050 inPath
, RTL_TEXTENCODING_UTF8
),
1054 for ( n
= 0; n
< nPropCount
; ++n
)
1056 free( (void *)pItems
[ n
].name
->name
);
1057 delete pItems
[ n
].name
;
1058 free( (void *)pItems
[ n
].value
);
1063 HandleError( theRetVal
);
1066 // -------------------------------------------------------------------
1068 // -------------------------------------------------------------------
1069 void NeonSession::HEAD( const ::rtl::OUString
& inPath
,
1070 const std::vector
< ::rtl::OUString
> & inHeaderNames
,
1071 DAVResource
& ioResource
,
1072 const DAVRequestEnvironment
& rEnv
)
1073 throw( DAVException
)
1075 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1081 int theRetVal
= NE_OK
;
1082 NeonHeadRequest
theRequest( m_pHttpSession
,
1087 HandleError( theRetVal
);
1090 // -------------------------------------------------------------------
1092 // -------------------------------------------------------------------
1093 uno::Reference
< io::XInputStream
>
1094 NeonSession::GET( const rtl::OUString
& inPath
,
1095 const DAVRequestEnvironment
& rEnv
)
1096 throw ( DAVException
)
1098 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1104 rtl::Reference
< NeonInputStream
> xInputStream( new NeonInputStream
);
1105 NeonRequestContext
aCtx( xInputStream
);
1106 int theRetVal
= GET( m_pHttpSession
,
1107 rtl::OUStringToOString(
1108 inPath
, RTL_TEXTENCODING_UTF8
),
1109 NeonSession_ResponseBlockReader
,
1112 HandleError( theRetVal
);
1113 return uno::Reference
< io::XInputStream
>( xInputStream
.get() );
1116 // -------------------------------------------------------------------
1118 // -------------------------------------------------------------------
1119 void NeonSession::GET( const rtl::OUString
& inPath
,
1120 uno::Reference
< io::XOutputStream
> & ioOutputStream
,
1121 const DAVRequestEnvironment
& rEnv
)
1122 throw ( DAVException
)
1124 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1130 NeonRequestContext
aCtx( ioOutputStream
);
1131 int theRetVal
= GET( m_pHttpSession
,
1132 rtl::OUStringToOString(
1133 inPath
, RTL_TEXTENCODING_UTF8
),
1134 NeonSession_ResponseBlockWriter
,
1137 HandleError( theRetVal
);
1140 // -------------------------------------------------------------------
1142 // -------------------------------------------------------------------
1143 uno::Reference
< io::XStream
>
1144 NeonSession::GET( const rtl::OUString
& inPath
,
1145 const std::vector
< ::rtl::OUString
> & inHeaderNames
,
1146 DAVResource
& ioResource
,
1147 const DAVRequestEnvironment
& rEnv
,
1148 sal_Bool bAllowEmpty
)
1149 throw ( DAVException
)
1151 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1157 ioResource
.uri
= inPath
;
1158 ioResource
.properties
.clear();
1160 rtl::Reference
< NeonInputStream
> xStream( new NeonInputStream
);
1161 NeonRequestContext
aCtx( xStream
, inHeaderNames
, ioResource
);
1162 int theRetVal
= GET( m_pHttpSession
,
1163 rtl::OUStringToOString(
1164 inPath
, RTL_TEXTENCODING_UTF8
),
1165 NeonSession_ResponseBlockReader
,
1169 HandleError( theRetVal
);
1171 catch ( DAVException
const & e
)
1173 if ( !bAllowEmpty
|| ( e
.getStatus() != SC_NOT_FOUND
) )
1176 return uno::Reference
< io::XStream
>( xStream
.get() );
1179 // -------------------------------------------------------------------
1181 // -------------------------------------------------------------------
1182 void NeonSession::GET( const rtl::OUString
& inPath
,
1183 uno::Reference
< io::XOutputStream
> & ioOutputStream
,
1184 const std::vector
< ::rtl::OUString
> & inHeaderNames
,
1185 DAVResource
& ioResource
,
1186 const DAVRequestEnvironment
& rEnv
)
1187 throw ( DAVException
)
1189 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1195 ioResource
.uri
= inPath
;
1196 ioResource
.properties
.clear();
1198 NeonRequestContext
aCtx( ioOutputStream
, inHeaderNames
, ioResource
);
1199 int theRetVal
= GET( m_pHttpSession
,
1200 rtl::OUStringToOString(
1201 inPath
, RTL_TEXTENCODING_UTF8
),
1202 NeonSession_ResponseBlockWriter
,
1205 HandleError( theRetVal
);
1208 // -------------------------------------------------------------------
1210 // -------------------------------------------------------------------
1211 void NeonSession::PUT( const rtl::OUString
& inPath
,
1212 const uno::Reference
< io::XInputStream
> & inInputStream
,
1213 const DAVRequestEnvironment
& rEnv
)
1214 throw ( DAVException
)
1216 // initialization etc. is performed in the other PUT
1218 uno::Sequence
< sal_Int8
> aDataToSend
;
1219 if ( !getDataFromInputStream( inInputStream
, aDataToSend
, false ) )
1220 throw DAVException( DAVException::DAV_INVALID_ARG
);
1223 reinterpret_cast< const char * >( aDataToSend
.getConstArray() ),
1224 aDataToSend
.getLength(),
1228 // -------------------------------------------------------------------
1230 // -------------------------------------------------------------------
1231 void NeonSession::PUT( const rtl::OUString
&inPath
,
1232 const char * buffer
,
1234 const DAVRequestEnvironment
& rEnv
)
1235 throw ( DAVException
)
1237 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1243 int theRetVal
= PUT( m_pHttpSession
,
1244 rtl::OUStringToOString(
1245 inPath
, RTL_TEXTENCODING_UTF8
),
1249 HandleError( theRetVal
);
1252 // -------------------------------------------------------------------
1254 // -------------------------------------------------------------------
1255 uno::Reference
< io::XInputStream
>
1256 NeonSession::POST( const rtl::OUString
& inPath
,
1257 const rtl::OUString
& rContentType
,
1258 const rtl::OUString
& rReferer
,
1259 const uno::Reference
< io::XInputStream
> & inInputStream
,
1260 const DAVRequestEnvironment
& rEnv
)
1261 throw ( DAVException
)
1263 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1265 uno::Sequence
< sal_Int8
> aDataToSend
;
1266 if ( !getDataFromInputStream( inInputStream
, aDataToSend
, true ) )
1267 throw DAVException( DAVException::DAV_INVALID_ARG
);
1273 rtl::Reference
< NeonInputStream
> xInputStream( new NeonInputStream
);
1274 NeonRequestContext
aCtx( xInputStream
);
1275 int theRetVal
= POST( m_pHttpSession
,
1276 rtl::OUStringToOString(
1277 inPath
, RTL_TEXTENCODING_UTF8
),
1278 reinterpret_cast< const char * >(
1279 aDataToSend
.getConstArray() ),
1280 NeonSession_ResponseBlockReader
,
1285 HandleError( theRetVal
);
1286 return uno::Reference
< io::XInputStream
>( xInputStream
.get() );
1289 // -------------------------------------------------------------------
1291 // -------------------------------------------------------------------
1292 void NeonSession::POST( const rtl::OUString
& inPath
,
1293 const rtl::OUString
& rContentType
,
1294 const rtl::OUString
& rReferer
,
1295 const uno::Reference
< io::XInputStream
> & inInputStream
,
1296 uno::Reference
< io::XOutputStream
> & oOutputStream
,
1297 const DAVRequestEnvironment
& rEnv
)
1298 throw ( DAVException
)
1300 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1302 uno::Sequence
< sal_Int8
> aDataToSend
;
1303 if ( !getDataFromInputStream( inInputStream
, aDataToSend
, true ) )
1304 throw DAVException( DAVException::DAV_INVALID_ARG
);
1310 NeonRequestContext
aCtx( oOutputStream
);
1311 int theRetVal
= POST( m_pHttpSession
,
1312 rtl::OUStringToOString(
1313 inPath
, RTL_TEXTENCODING_UTF8
),
1314 reinterpret_cast< const char * >(
1315 aDataToSend
.getConstArray() ),
1316 NeonSession_ResponseBlockWriter
,
1321 HandleError( theRetVal
);
1324 // -------------------------------------------------------------------
1326 // -------------------------------------------------------------------
1327 void NeonSession::ABORT()
1328 throw ( DAVException
)
1330 if (NULL
!=m_pHttpSession
)
1331 ne_close_connection(m_pHttpSession
);
1334 // -------------------------------------------------------------------
1336 // -------------------------------------------------------------------
1337 void NeonSession::MKCOL( const rtl::OUString
& inPath
,
1338 const DAVRequestEnvironment
& rEnv
)
1339 throw ( DAVException
)
1341 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1347 int theRetVal
= ne_mkcol( m_pHttpSession
,
1348 rtl::OUStringToOString(
1349 inPath
, RTL_TEXTENCODING_UTF8
) );
1350 HandleError( theRetVal
);
1353 // -------------------------------------------------------------------
1355 // -------------------------------------------------------------------
1356 void NeonSession::COPY( const rtl::OUString
& inSourceURL
,
1357 const rtl::OUString
& inDestinationURL
,
1358 const DAVRequestEnvironment
& rEnv
,
1359 sal_Bool inOverWrite
)
1360 throw ( DAVException
)
1362 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1368 NeonUri
theSourceUri( inSourceURL
);
1369 NeonUri
theDestinationUri( inDestinationURL
);
1371 int theRetVal
= ne_copy( m_pHttpSession
,
1372 inOverWrite
? 1 : 0,
1374 rtl::OUStringToOString(
1375 theSourceUri
.GetPath(),
1376 RTL_TEXTENCODING_UTF8
),
1377 rtl::OUStringToOString(
1378 theDestinationUri
.GetPath(),
1379 RTL_TEXTENCODING_UTF8
) );
1380 HandleError( theRetVal
);
1383 // -------------------------------------------------------------------
1385 // -------------------------------------------------------------------
1386 void NeonSession::MOVE( const rtl::OUString
& inSourceURL
,
1387 const rtl::OUString
& inDestinationURL
,
1388 const DAVRequestEnvironment
& rEnv
,
1389 sal_Bool inOverWrite
)
1390 throw ( DAVException
)
1392 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1398 NeonUri
theSourceUri( inSourceURL
);
1399 NeonUri
theDestinationUri( inDestinationURL
);
1400 int theRetVal
= ne_move( m_pHttpSession
,
1401 inOverWrite
? 1 : 0,
1402 rtl::OUStringToOString(
1403 theSourceUri
.GetPath(),
1404 RTL_TEXTENCODING_UTF8
),
1405 rtl::OUStringToOString(
1406 theDestinationUri
.GetPath(),
1407 RTL_TEXTENCODING_UTF8
) );
1408 HandleError( theRetVal
);
1411 // -------------------------------------------------------------------
1413 // -------------------------------------------------------------------
1414 void NeonSession::DESTROY( const rtl::OUString
& inPath
,
1415 const DAVRequestEnvironment
& rEnv
)
1416 throw ( DAVException
)
1418 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1424 int theRetVal
= ne_delete( m_pHttpSession
,
1425 rtl::OUStringToOString(
1426 inPath
, RTL_TEXTENCODING_UTF8
) );
1427 HandleError( theRetVal
);
1430 // -------------------------------------------------------------------
1432 // -------------------------------------------------------------------
1433 void NeonSession::LOCK( ucb::Lock
& rLock
,
1434 const DAVRequestEnvironment
& rEnv
)
1435 throw ( DAVException
)
1437 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1443 Lockit( rLock
, true );
1446 // -------------------------------------------------------------------
1448 // -------------------------------------------------------------------
1449 void NeonSession::UNLOCK( ucb::Lock
& rLock
,
1450 const DAVRequestEnvironment
& rEnv
)
1451 throw ( DAVException
)
1453 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1459 Lockit( rLock
, false );
1462 // -------------------------------------------------------------------
1463 const ucbhelper::InternetProxyServer
& NeonSession::getProxySettings() const
1465 if ( m_aScheme
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "http" ) ) ||
1466 m_aScheme
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "https" ) ) )
1468 return m_rProxyDecider
.getProxy( m_aScheme
,
1474 return m_rProxyDecider
.getProxy( m_aScheme
,
1475 rtl::OUString() /* not used */,
1476 -1 /* not used */ );
1480 // -------------------------------------------------------------------
1482 // Common Error Handler
1483 // -------------------------------------------------------------------
1484 void NeonSession::HandleError( int nError
)
1485 throw ( DAVException
)
1487 m_aEnv
= DAVRequestEnvironment();
1489 // Map error code to DAVException.
1496 case NE_ERROR
: // Generic error
1498 rtl::OUString aText
= rtl::OUString::createFromAscii(
1499 ne_get_error( m_pHttpSession
) );
1500 #if OSL_DEBUG_LEVEL > 0
1501 fprintf( stderr
, "WebDAV: got error '%s'\n", rtl::OUStringToOString( aText
, RTL_TEXTENCODING_UTF8
).getStr() );
1503 throw DAVException( DAVException::DAV_HTTP_ERROR
,
1505 makeStatusCode( aText
) );
1508 case NE_LOOKUP
: // Name lookup failed.
1509 throw DAVException( DAVException::DAV_HTTP_LOOKUP
,
1510 NeonUri::makeConnectionEndPointString(
1511 m_aHostName
, m_nPort
) );
1513 case NE_AUTH
: // User authentication failed on server
1514 throw DAVException( DAVException::DAV_HTTP_AUTH
,
1515 NeonUri::makeConnectionEndPointString(
1516 m_aHostName
, m_nPort
) );
1518 case NE_PROXYAUTH
: // User authentication failed on proxy
1519 throw DAVException( DAVException::DAV_HTTP_AUTHPROXY
,
1520 NeonUri::makeConnectionEndPointString(
1521 m_aProxyName
, m_nProxyPort
) );
1523 case NE_CONNECT
: // Could not connect to server
1524 throw DAVException( DAVException::DAV_HTTP_CONNECT
,
1525 NeonUri::makeConnectionEndPointString(
1526 m_aHostName
, m_nPort
) );
1528 case NE_TIMEOUT
: // Connection timed out
1529 throw DAVException( DAVException::DAV_HTTP_TIMEOUT
,
1530 NeonUri::makeConnectionEndPointString(
1531 m_aHostName
, m_nPort
) );
1533 case NE_FAILED
: // The precondition failed
1534 throw DAVException( DAVException::DAV_HTTP_FAILED
,
1535 NeonUri::makeConnectionEndPointString(
1536 m_aHostName
, m_nPort
) );
1538 case NE_RETRY
: // Retry request (ne_end_request ONLY)
1539 throw DAVException( DAVException::DAV_HTTP_RETRY
,
1540 NeonUri::makeConnectionEndPointString(
1541 m_aHostName
, m_nPort
) );
1545 NeonUri
aUri( ne_redirect_location( m_pHttpSession
) );
1547 DAVException::DAV_HTTP_REDIRECT
, aUri
.GetURI() );
1551 OSL_TRACE( "NeonSession::HandleError : Unknown Neon error code!" );
1552 throw DAVException( DAVException::DAV_HTTP_ERROR
,
1553 rtl::OUString::createFromAscii(
1554 ne_get_error( m_pHttpSession
) ) );
1559 void NeonSession::Lockit( ucb::Lock
& rLock
, bool bLockit
)
1560 throw ( DAVException
)
1562 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1564 if ( !s_aNeonLockStore
)
1565 throw DAVException( DAVException::DAV_INVALID_ARG
);
1568 ne_uri_parse( rtl::OUStringToOString( m_aEnv
.m_aRequestURI
, RTL_TEXTENCODING_UTF8
).getStr(),
1571 #if NEON_VERSION < 0x0260
1572 #define FILLIN( field, val ) aUri.field = aUri.field? aUri.field: strdup( rtl::OUStringToOString( val, RTL_TEXTENCODING_UTF8 ).getStr() )
1573 FILLIN( scheme
, m_aScheme
);
1574 FILLIN( host
, m_aHostName
);
1575 aUri
.port
= aUri
.port
? aUri
.port
: m_nPort
;
1579 // Create the neon lock
1580 NeonLock
* theLock
= ne_lockstore_findbyuri( s_aNeonLockStore
, &aUri
);
1581 bool bAlreadyExists
= false;
1583 bAlreadyExists
= true;
1586 theLock
= ne_lock_create();
1589 theLock
->uri
= aUri
;
1591 // Set the lock depth
1592 switch( rLock
.Depth
)
1594 case ucb::LockDepth_ZERO
: theLock
->depth
= NE_DEPTH_ZERO
; break;
1595 case ucb::LockDepth_ONE
: theLock
->depth
= NE_DEPTH_ONE
; break;
1596 case ucb::LockDepth_INFINITY
: theLock
->depth
= NE_DEPTH_INFINITE
; break;
1598 throw DAVException( DAVException::DAV_INVALID_ARG
);
1601 // Set the lock scope
1602 switch ( rLock
.Scope
)
1604 case ucb::LockScope_EXCLUSIVE
: theLock
->scope
= ne_lockscope_exclusive
; break;
1605 case ucb::LockScope_SHARED
: theLock
->scope
= ne_lockscope_shared
; break;
1607 throw DAVException( DAVException::DAV_INVALID_ARG
);
1611 // Set the lock owner
1612 rtl::OUString aValue
;
1613 rLock
.Owner
>>= aValue
;
1615 theLock
->owner
= strdup( rtl::OUStringToOString( aValue
, RTL_TEXTENCODING_UTF8
).getStr() );
1617 // Set the lock timeout
1618 // We re-new the lock while the stream is open
1619 theLock
->timeout
= rLock
.Timeout
;
1625 if ( bAlreadyExists
)
1627 #if NEON_VERSION >= 0x0260
1628 nRet
= ne_lock_refresh( m_pHttpSession
, theLock
);
1630 // workaround for a bug in neon 0.24
1631 // we have to call with a bigger structure that is used internally
1632 // and initialize parts of it
1636 struct ne_lock active
; /* activelock */
1637 char *token
; /* the token we're after. */
1642 struct lock_ctx ctx
;
1644 memset( &ctx
, 0, sizeof ctx
);
1645 ctx
.cdata
= ne_buffer_create();
1647 memcpy( &ctx
, theLock
, sizeof( *theLock
) );
1648 nRet
= ne_lock_refresh( m_pHttpSession
, reinterpret_cast<NeonLock
*>( &ctx
) );
1650 ne_buffer_destroy( ctx
.cdata
);
1652 if ( ( nRet
== NE_ERROR
) && strncmp (ne_get_error (m_pHttpSession
), "No activelock ", strlen ("No activelock ")) == 0 )
1654 bAlreadyExists
= false;
1655 ne_lockstore_remove( s_aNeonLockStore
, theLock
);
1658 if ( !bAlreadyExists
)
1660 nRet
= ne_lock( m_pHttpSession
, theLock
);
1662 if ( nRet
== NE_OK
)
1664 ne_lockstore_add( s_aNeonLockStore
, theLock
);
1666 uno::Sequence
< rtl::OUString
> aTokens( 1 );
1667 aTokens
[0] = rtl::OUString::createFromAscii( theLock
->token
);
1668 rLock
.LockTokens
= aTokens
;
1670 #if OSL_DEBUG_LEVEL > 0
1671 fprintf( stderr
, "WebDAV: locked the URL, the token is: %s\n", theLock
->token
);
1676 if ( ( nRet
== NE_ERROR
) && getStatusCode( m_pHttpSession
) == SC_LOCKED
)
1678 ucbhelper::cancelCommandExecution( ucb::IOErrorCode_LOCKING_VIOLATION
,
1679 uno::Sequence
< uno::Any
>( 0 ), // FIXME more info about the file?
1681 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "a locking error occured" ) ),
1682 uno::Reference
< ucb::XCommandProcessor
>() );
1684 #if OSL_DEBUG_LEVEL > 0
1685 else if ( nRet
== NE_OK
)
1686 fprintf( stderr
, "WebDAV: locked/refreshed lock OK\n" );
1688 fprintf( stderr
, "WebDAV: failed to lock the file: %s\n", ne_get_error( m_pHttpSession
) );
1693 // Set the lock token
1694 if ( rLock
.LockTokens
.getLength() > 0 )
1696 rtl::OUString theToken
= rLock
.LockTokens
.getConstArray()[ 0 ];
1697 theLock
->token
= strdup( rtl::OUStringToOString( theToken
, RTL_TEXTENCODING_UTF8
).getStr() );
1699 #if OSL_DEBUG_LEVEL > 0
1700 fprintf( stderr
, "WebDAV: going to unlock the URL, the token is: %s\n", theLock
->token
);
1703 ne_unlock( m_pHttpSession
, theLock
);
1704 ne_lockstore_remove( s_aNeonLockStore
, theLock
);
1705 // FIXME even ne_lock_destroy( theLock )?
1710 // -------------------------------------------------------------------
1713 void runResponseHeaderHandler( void * userdata
,
1714 const char * value
)
1716 rtl::OUString
aHeader( rtl::OUString::createFromAscii( value
) );
1717 sal_Int32 nPos
= aHeader
.indexOf( ':' );
1721 rtl::OUString
aHeaderName( aHeader
.copy( 0, nPos
) );
1723 NeonRequestContext
* pCtx
1724 = static_cast< NeonRequestContext
* >( userdata
);
1726 // Note: Empty vector means that all headers are requested.
1727 bool bIncludeIt
= ( pCtx
->pHeaderNames
->size() == 0 );
1731 // Check whether this header was requested.
1732 std::vector
< ::rtl::OUString
>::const_iterator
it(
1733 pCtx
->pHeaderNames
->begin() );
1734 const std::vector
< ::rtl::OUString
>::const_iterator
end(
1735 pCtx
->pHeaderNames
->end() );
1739 // header names are case insensitive
1740 if ( (*it
).equalsIgnoreAsciiCase( aHeaderName
) )
1742 aHeaderName
= (*it
);
1754 // Create & set the PropertyValue
1755 DAVPropertyValue thePropertyValue
;
1756 thePropertyValue
.IsCaseSensitive
= false;
1757 thePropertyValue
.Name
= aHeaderName
;
1759 if ( nPos
< aHeader
.getLength() )
1760 thePropertyValue
.Value
<<= aHeader
.copy( nPos
+ 1 ).trim();
1762 // Add the newly created PropertyValue
1763 pCtx
->pResource
->properties
.push_back( thePropertyValue
);
1770 // -------------------------------------------------------------------
1772 int NeonSession::GET( ne_session
* sess
,
1774 ne_block_reader reader
,
1778 //struct get_context ctx;
1779 ne_request
* req
= ne_request_create( sess
, "GET", uri
);
1781 void *cursor
= NULL
;
1782 const char *name
, *value
;
1784 #if NEON_VERSION < 0x0250
1786 ne_add_response_header_catcher( req
, runResponseHeaderHandler
, userdata
);
1788 ne_add_response_body_reader( req
, ne_accept_2xx
, reader
, userdata
);
1790 ret
= ne_request_dispatch( req
);
1792 #if NEON_VERSION >= 0x0250
1795 while ((cursor
= ne_response_header_iterate(req
, cursor
, &name
, &value
))
1800 ne_snprintf(buffer
, sizeof buffer
, "%s: %s", name
, value
);
1802 runResponseHeaderHandler(userdata
, buffer
);
1806 if ( ret
== NE_OK
&& ne_get_status( req
)->klass
!= 2 )
1809 ne_request_destroy( req
);
1813 // -------------------------------------------------------------------
1815 int NeonSession::PUT( ne_session
* sess
,
1817 const char * buffer
,
1820 ne_request
* req
= ne_request_create( sess
, "PUT", uri
);
1823 ne_lock_using_resource( req
, uri
, 0 );
1824 ne_lock_using_parent( req
, uri
);
1826 ne_set_request_body_buffer( req
, buffer
, size
);
1828 ret
= ne_request_dispatch( req
);
1830 if ( ret
== NE_OK
&& ne_get_status( req
)->klass
!= 2 )
1833 ne_request_destroy( req
);
1837 // -------------------------------------------------------------------
1838 int NeonSession::POST( ne_session
* sess
,
1840 const char * buffer
,
1841 ne_block_reader reader
,
1843 const rtl::OUString
& rContentType
,
1844 const rtl::OUString
& rReferer
)
1846 ne_request
* req
= ne_request_create( sess
, "POST", uri
);
1847 //struct get_context ctx;
1850 RequestDataMap
* pData
= 0;
1852 if ( rContentType
.getLength() || rReferer
.getLength() )
1854 // Remember contenttype and referer. Data will be added to HTTP request
1855 // header in in 'PreSendRequest' callback.
1856 pData
= static_cast< RequestDataMap
* >( m_pRequestData
);
1857 (*pData
)[ req
] = RequestData( rContentType
, rReferer
);
1863 //ctx.session = sess;
1865 ///* Read the value of the Content-Length header into ctx.total */
1866 //ne_add_response_header_handler( req, "Content-Length",
1867 // ne_handle_numeric_header, &ctx.total );
1869 ne_add_response_body_reader( req
, ne_accept_2xx
, reader
, userdata
);
1871 ne_set_request_body_buffer( req
, buffer
, strlen( buffer
) );
1873 ret
= ne_request_dispatch( req
);
1878 if ( ret
== NE_OK
&& ne_get_status( req
)->klass
!= 2 )
1881 ne_request_destroy( req
);
1885 // Remove request data from session's list.
1886 RequestDataMap::iterator it
= pData
->find( req
);
1887 if ( it
!= pData
->end() )
1894 // -------------------------------------------------------------------
1896 bool NeonSession::getDataFromInputStream(
1897 const uno::Reference
< io::XInputStream
> & xStream
,
1898 uno::Sequence
< sal_Int8
> & rData
,
1899 bool bAppendTrailingZeroByte
)
1903 uno::Reference
< io::XSeekable
> xSeekable( xStream
, uno::UNO_QUERY
);
1904 if ( xSeekable
.is() )
1909 = sal::static_int_cast
<sal_Int32
>(xSeekable
->getLength());
1911 = xStream
->readBytes( rData
, nSize
);
1913 if ( nRead
== nSize
)
1915 if ( bAppendTrailingZeroByte
)
1917 rData
.realloc( nSize
+ 1 );
1918 rData
[ nSize
] = sal_Int8( 0 );
1923 catch ( io::NotConnectedException
const & )
1927 catch ( io::BufferSizeExceededException
const & )
1931 catch ( io::IOException
const & )
1933 // getLength, readBytes
1940 uno::Sequence
< sal_Int8
> aBuffer
;
1943 sal_Int32 nRead
= xStream
->readSomeBytes( aBuffer
, 65536 );
1946 if ( rData
.getLength() < ( nPos
+ nRead
) )
1947 rData
.realloc( nPos
+ nRead
);
1949 aBuffer
.realloc( nRead
);
1950 rtl_copyMemory( (void*)( rData
.getArray() + nPos
),
1951 (const void*)aBuffer
.getConstArray(),
1955 aBuffer
.realloc( 0 );
1956 nRead
= xStream
->readSomeBytes( aBuffer
, 65536 );
1959 if ( bAppendTrailingZeroByte
)
1961 rData
.realloc( nPos
+ 1 );
1962 rData
[ nPos
] = sal_Int8( 0 );
1966 catch ( io::NotConnectedException
const & )
1970 catch ( io::BufferSizeExceededException
const & )
1974 catch ( io::IOException
const & )
1982 // -------------------------------------------------------------------
1985 NeonSession::Map
NeonSession::certMap
;
1987 // ---------------------------------------------------------------------
1989 NeonSession::isDomainMatch( rtl::OUString certHostName
)
1991 rtl::OUString hostName
= getHostName();
1993 if (hostName
.equalsIgnoreAsciiCase( certHostName
))
1998 if ( 0 == certHostName
.indexOf( rtl::OUString::createFromAscii( "*" ) ) && hostName
.getLength() >= certHostName
.getLength() )
2000 rtl::OUString cmpStr
= certHostName
.copy( 1 );
2002 if ( hostName
.matchIgnoreAsciiCase( cmpStr
, hostName
.getLength( ) - cmpStr
.getLength()) )