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"
46 #include "ucbhelper/simplecertificatevalidationrequest.hxx"
48 #include "DAVAuthListener.hxx"
49 #include "NeonTypes.hxx"
50 #include "NeonSession.hxx"
51 #include "NeonInputStream.hxx"
52 #include "NeonPropFindRequest.hxx"
53 #include "NeonHeadRequest.hxx"
54 #include "NeonUri.hxx"
55 #include "LinkSequence.hxx"
56 #include "UCBDeadPropertyValue.hxx"
58 #include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
59 #include <com/sun/star/security/XCertificate.hpp>
60 #include <com/sun/star/security/CertificateValidity.hpp>
61 #include <com/sun/star/security/CertificateContainerStatus.hpp>
62 #include <com/sun/star/security/CertificateContainer.hpp>
63 #include <com/sun/star/security/XCertificateContainer.hpp>
64 #include <com/sun/star/task/XMasterPasswordHandling.hpp>
65 #include <com/sun/star/xml/crypto/XSEInitializer.hpp>
67 using namespace com::sun::star
;
68 using namespace webdav_ucp
;
70 #define SEINITIALIZER_COMPONENT "com.sun.star.xml.crypto.SEInitializer"
75 #include <ucbhelper/cancelcommandexecution.hxx>
77 // -------------------------------------------------------------------
79 // -------------------------------------------------------------------
84 rtl::OUString aContentType
;
85 rtl::OUString aReferer
;
88 RequestData( const rtl::OUString
& rContentType
,
89 const rtl::OUString
& rReferer
)
90 : aContentType( rContentType
), aReferer( rReferer
) {}
93 // -------------------------------------------------------------------
95 // -------------------------------------------------------------------
99 bool operator()( const ne_request
* p1
, const ne_request
* p2
) const
107 size_t operator()( const ne_request
* p
) const
113 typedef std::hash_map
122 // -------------------------------------------------------------------
124 bool NeonSession::m_bGlobalsInited
= false;
125 osl::Mutex
NeonSession::m_aGlobalMutex
;
126 // -------------------------------------------------------------------
128 // -------------------------------------------------------------------
129 static sal_uInt16
makeStatusCode( const rtl::OUString
& rStatusText
)
131 // Extract status code from session error string. Unfortunately
132 // neon provides no direct access to the status code...
134 if ( rStatusText
.getLength() < 3 )
137 sal_False
, "makeStatusCode - status text string to short!" );
141 sal_Int32 nPos
= rStatusText
.indexOf( ' ' );
144 OSL_ENSURE( sal_False
, "makeStatusCode - wrong status text format!" );
148 return sal_uInt16( rStatusText
.copy( 0, nPos
).toInt32() );
151 static sal_uInt16
getStatusCode( HttpSession
*pSession
)
153 rtl::OUString aText
= rtl::OUString::createFromAscii( ne_get_error( pSession
) );
154 return makeStatusCode( aText
);
157 // -------------------------------------------------------------------
158 struct NeonRequestContext
160 uno::Reference
< io::XOutputStream
> xOutputStream
;
161 rtl::Reference
< NeonInputStream
> xInputStream
;
162 const std::vector
< ::rtl::OUString
> * pHeaderNames
;
163 DAVResource
* pResource
;
165 NeonRequestContext( uno::Reference
< io::XOutputStream
> & xOutStrm
)
166 : xOutputStream( xOutStrm
), xInputStream( 0 ),
167 pHeaderNames( 0 ), pResource( 0 ) {}
169 NeonRequestContext( const rtl::Reference
< NeonInputStream
> & xInStrm
)
170 : xOutputStream( 0 ), xInputStream( xInStrm
),
171 pHeaderNames( 0 ), pResource( 0 ) {}
173 NeonRequestContext( uno::Reference
< io::XOutputStream
> & xOutStrm
,
174 const std::vector
< ::rtl::OUString
> & inHeaderNames
,
175 DAVResource
& ioResource
)
176 : xOutputStream( xOutStrm
), xInputStream( 0 ),
177 pHeaderNames( &inHeaderNames
), pResource( &ioResource
) {}
179 NeonRequestContext( const rtl::Reference
< NeonInputStream
> & xInStrm
,
180 const std::vector
< ::rtl::OUString
> & inHeaderNames
,
181 DAVResource
& ioResource
)
182 : xOutputStream( 0 ), xInputStream( xInStrm
),
183 pHeaderNames( &inHeaderNames
), pResource( &ioResource
) {}
186 //--------------------------------------------------------------------
187 //--------------------------------------------------------------------
189 // Callback functions
191 //--------------------------------------------------------------------
192 //--------------------------------------------------------------------
194 // -------------------------------------------------------------------
195 // ResponseBlockReader
196 // A simple Neon response_block_reader for use with an XInputStream
197 // -------------------------------------------------------------------
199 #if NEON_VERSION >= 0x0250
204 NeonSession_ResponseBlockReader( void * inUserData
,
208 // neon calls this function with (inLen == 0)...
211 NeonRequestContext
* pCtx
212 = static_cast< NeonRequestContext
* >( inUserData
);
214 rtl::Reference
< NeonInputStream
> xInputStream(
217 if ( xInputStream
.is() )
218 xInputStream
->AddToStream( inBuf
, inLen
);
220 #if NEON_VERSION >= 0x0250
225 // -------------------------------------------------------------------
226 // ResponseBlockWriter
227 // A simple Neon response_block_reader for use with an XOutputStream
228 // -------------------------------------------------------------------
230 #if NEON_VERSION >= 0x0250
235 NeonSession_ResponseBlockWriter( void * inUserData
,
239 // neon calls this function with (inLen == 0)...
242 NeonRequestContext
* pCtx
243 = static_cast< NeonRequestContext
* >( inUserData
);
244 uno::Reference
< io::XOutputStream
> xOutputStream
245 = pCtx
->xOutputStream
;
247 if ( xOutputStream
.is() )
249 const uno::Sequence
< sal_Int8
> aSeq( (sal_Int8
*)inBuf
, inLen
);
250 xOutputStream
->writeBytes( aSeq
);
253 #if NEON_VERSION >= 0x0250
258 // -------------------------------------------------------------------
259 extern "C" int NeonSession_NeonAuth( void * inUserData
,
260 #ifdef NE_FEATURE_SSPI
261 const char * inAuthProtocol
,
263 const char * inRealm
,
265 char * inoutUserName
,
266 char * inoutPassWord
)
268 /* The callback used to request the username and password in the given
269 * realm. The username and password must be copied into the buffers
270 * which are both of size NE_ABUFSIZ. The 'attempt' parameter is zero
271 * on the first call to the callback, and increases by one each time
272 * an attempt to authenticate fails.
274 * The callback must return zero to indicate that authentication
275 * should be attempted with the username/password, or non-zero to
276 * cancel the request. (if non-zero, username and password are
280 // Give'em only a limited mumber of retries..
288 NeonSession
* theSession
= static_cast< NeonSession
* >( inUserData
);
289 DAVAuthListener
* pListener
290 = theSession
->getRequestEnvironment().m_xAuthListener
.get();
296 rtl::OUString theUserName
;
297 rtl::OUString thePassWord
;
301 // neon does not handle username supplied with request URI (for
302 // instance when doing FTP over proxy - last checked: 0.23.5 )
306 rtl::OUString
aUserInfo( theSession
->getUserInfo() );
307 if ( aUserInfo
.getLength() )
309 sal_Int32 nPos
= aUserInfo
.indexOf( ':' );
312 theUserName
= aUserInfo
;
316 theUserName
= aUserInfo
.copy( 0, nPos
);
317 thePassWord
= aUserInfo
.copy( nPos
+ 1 );
321 catch ( DAVException
const & )
329 // username buffer is prefilled with user name from last attempt.
330 theUserName
= rtl::OUString::createFromAscii( inoutUserName
);
331 // @@@ Neon does not initialize password buffer (last checked: 0.22.0).
332 //thePassWord = rtl::OUString::createFromAscii( inoutPassWord );
335 bool bCanUseSystemCreds
= false;
337 #ifdef NE_FEATURE_SSPI
338 bCanUseSystemCreds
= (attempt
== 0) && // avoid endless loops
339 ne_has_support( NE_FEATURE_SSPI
) && // Windows-only feature.
340 ( ne_strcasecmp( inAuthProtocol
, "NTLM" ) == 0 ) ||
341 ( ne_strcasecmp( inAuthProtocol
, "Negotiate" ) == 0 );
344 // #i97003# (tkr): Ask XMasterPasswordHandling if we should store the
345 // credentials persistently and give this information to the auth listener
346 uno::Reference
< task::XMasterPasswordHandling
> xMasterPasswordHandling
;
349 xMasterPasswordHandling
=
350 uno::Reference
< task::XMasterPasswordHandling
>(
351 theSession
->getMSF()->createInstance(
352 rtl::OUString::createFromAscii(
353 "com.sun.star.task.PasswordContainer" )),
356 catch ( uno::Exception
const & )
360 int theRetVal
= pListener
->authenticate(
361 rtl::OUString::createFromAscii( inRealm
),
362 theSession
->getHostName(),
365 xMasterPasswordHandling
.is()
366 ? xMasterPasswordHandling
->
367 isPersistentStoringAllowed()
372 rtl::OUStringToOString( theUserName
, RTL_TEXTENCODING_UTF8
) );
373 if ( aUser
.getLength() > ( NE_ABUFSIZ
- 1 ) )
376 sal_False
, "NeonSession_NeonAuth - username to long!" );
381 rtl::OUStringToOString( thePassWord
, RTL_TEXTENCODING_UTF8
) );
382 if ( aPass
.getLength() > ( NE_ABUFSIZ
- 1 ) )
385 sal_False
, "NeonSession_NeonAuth - password to long!" );
389 strcpy( inoutUserName
, // #100211# - checked
390 rtl::OUStringToOString( theUserName
, RTL_TEXTENCODING_UTF8
) );
392 strcpy( inoutPassWord
, // #100211# - checked
393 rtl::OUStringToOString( thePassWord
, RTL_TEXTENCODING_UTF8
) );
398 // -------------------------------------------------------------------
401 // -------------------------------------------------------------------
403 ::rtl::OUString
GetHostnamePart( const ::rtl::OUString
& _rRawString
)
405 ::rtl::OUString sPart
;
406 ::rtl::OUString sPartId
= ::rtl::OUString::createFromAscii( "CN=" );
407 sal_Int32 nContStart
= _rRawString
.indexOf( sPartId
);
408 if ( nContStart
!= -1 )
410 nContStart
= nContStart
+ sPartId
.getLength();
412 = _rRawString
.indexOf( sal_Unicode( ',' ), nContStart
);
413 sPart
= _rRawString
.copy( nContStart
, nContEnd
- nContStart
);
419 // -------------------------------------------------------------------
420 extern "C" int NeonSession_CertificationNotify( void *userdata
,
422 const ne_ssl_certificate
*cert
)
426 NeonSession
* pSession
= static_cast< NeonSession
* >( userdata
);
427 uno::Reference
< security::XCertificateContainer
> xCertificateContainer
;
430 xCertificateContainer
431 = uno::Reference
< security::XCertificateContainer
>(
432 pSession
->getMSF()->createInstance(
433 rtl::OUString::createFromAscii(
434 "com.sun.star.security.CertificateContainer" ) ),
437 catch ( uno::Exception
const & )
441 if ( !xCertificateContainer
.is() )
446 char * dn
= ne_ssl_readable_dname( ne_ssl_cert_subject( cert
) );
447 rtl::OUString
cert_subject( dn
, strlen( dn
), RTL_TEXTENCODING_UTF8
, 0 );
451 security::CertificateContainerStatus
certificateContainer(
452 xCertificateContainer
->hasCertificate(
453 pSession
->getHostName(), cert_subject
) );
455 if ( certificateContainer
!= security::CertificateContainerStatus_NOCERT
)
457 certificateContainer
== security::CertificateContainerStatus_TRUSTED
461 uno::Reference
< xml::crypto::XSEInitializer
> xSEInitializer
;
464 xSEInitializer
= uno::Reference
< xml::crypto::XSEInitializer
>(
465 pSession
->getMSF()->createInstance(
466 rtl::OUString::createFromAscii( SEINITIALIZER_COMPONENT
) ),
469 catch ( uno::Exception
const & )
473 if ( !xSEInitializer
.is() )
476 uno::Reference
< xml::crypto::XXMLSecurityContext
> xSecurityContext(
477 xSEInitializer
->createSecurityContext( rtl::OUString() ) );
479 uno::Reference
< xml::crypto::XSecurityEnvironment
> xSecurityEnv(
480 xSecurityContext
->getSecurityEnvironment() );
482 //The end entity certificate
483 char * eeCertB64
= ne_ssl_cert_export( cert
);
485 rtl::OString
sEECertB64( eeCertB64
);
487 uno::Reference
< com::sun::star::security::XCertificate
> xEECert(
488 xSecurityEnv
->createCertificateFromAscii(
489 rtl::OStringToOUString( sEECertB64
, RTL_TEXTENCODING_ASCII_US
) ) );
491 ne_free( eeCertB64
);
494 std::vector
< uno::Reference
< security::XCertificate
> > vecCerts
;
495 const ne_ssl_certificate
* issuerCert
= cert
;
498 //get the intermediate certificate
499 //the returned value is const ! Therfore it does not need to be freed
500 //with ne_ssl_cert_free, which takes a non-const argument
501 issuerCert
= ne_ssl_cert_signedby( issuerCert
);
502 if ( NULL
== issuerCert
)
505 char * imCertB64
= ne_ssl_cert_export( issuerCert
);
506 rtl::OString
sInterMediateCertB64( imCertB64
);
507 ne_free( imCertB64
);
509 uno::Reference
< security::XCertificate
> xImCert(
510 xSecurityEnv
->createCertificateFromAscii(
511 rtl::OStringToOUString(
512 sInterMediateCertB64
, RTL_TEXTENCODING_ASCII_US
) ) );
514 vecCerts
.push_back( xImCert
);
518 sal_Int64 certValidity
= xSecurityEnv
->verifyCertificate( xEECert
,
519 ::comphelper::containerToSequence( vecCerts
) );
521 if ( pSession
->isDomainMatch(
522 GetHostnamePart( xEECert
.get()->getSubjectName() ) ) )
524 // if host name matched with certificate then look if the
525 // certificate was ok
526 if( certValidity
== security::CertificateValidity::VALID
)
530 const uno::Reference
< ucb::XCommandEnvironment
> xEnv(
531 pSession
->getRequestEnvironment().m_xEnv
);
534 failures
= static_cast< int >( certValidity
);
536 uno::Reference
< task::XInteractionHandler
> xIH(
537 xEnv
->getInteractionHandler() );
540 rtl::Reference
< ucbhelper::SimpleCertificateValidationRequest
>
541 xRequest( new ucbhelper::SimpleCertificateValidationRequest(
542 (sal_Int32
)failures
, xEECert
, pSession
->getHostName() ) );
543 xIH
->handle( xRequest
.get() );
545 rtl::Reference
< ucbhelper::InteractionContinuation
> xSelection
546 = xRequest
->getSelection();
548 if ( xSelection
.is() )
550 uno::Reference
< task::XInteractionApprove
> xApprove(
551 xSelection
.get(), uno::UNO_QUERY
);
554 xCertificateContainer
->addCertificate(
555 pSession
->getHostName(), cert_subject
, sal_True
);
561 xCertificateContainer
->addCertificate(
562 pSession
->getHostName(), cert_subject
, sal_False
);
570 xCertificateContainer
->addCertificate(
571 pSession
->getHostName(), cert_subject
, sal_False
);
578 NeonLockStore
* NeonSession::s_aNeonLockStore
= NULL
;
580 // -------------------------------------------------------------------
581 extern "C" void NeonSession_PreSendRequest( ne_request
* req
,
583 ne_buffer
* headers
)
585 // userdata -> value returned by 'create'
587 NeonSession
* pSession
= static_cast< NeonSession
* >( userdata
);
590 // If there is a proxy server in between, it shall never use
591 // cached data. We always want 'up-to-date' data.
592 ne_buffer_concat( headers
, "Pragma: no-cache", EOL
, NULL
);
593 // alternative, but understoud by HTTP 1.1 servers only:
594 // ne_buffer_concat( headers, "Cache-Control: max-age=0", EOL, NULL );
596 const RequestDataMap
* pRequestData
597 = static_cast< const RequestDataMap
* >(
598 pSession
->getRequestData() );
600 RequestDataMap::const_iterator it
= pRequestData
->find( req
);
601 if ( it
!= pRequestData
->end() )
603 if ( (*it
).second
.aContentType
.getLength() )
605 char * pData
= headers
->data
;
606 if ( strstr( pData
, "Content-Type:" ) == NULL
)
609 = rtl::OUStringToOString( (*it
).second
.aContentType
,
610 RTL_TEXTENCODING_UTF8
);
611 ne_buffer_concat( headers
, "Content-Type: ",
612 aType
.getStr(), EOL
, NULL
);
616 if ( (*it
).second
.aReferer
.getLength() )
618 char * pData
= headers
->data
;
619 if ( strstr( pData
, "Referer:" ) == NULL
)
621 rtl::OString aReferer
622 = rtl::OUStringToOString( (*it
).second
.aReferer
,
623 RTL_TEXTENCODING_UTF8
);
624 ne_buffer_concat( headers
, "Referer: ",
625 aReferer
.getStr(), EOL
, NULL
);
630 const DAVRequestHeaders
& rHeaders
631 = pSession
->getRequestEnvironment().m_aRequestHeaders
;
633 DAVRequestHeaders::const_iterator
it1( rHeaders
.begin() );
634 const DAVRequestHeaders::const_iterator
end1( rHeaders
.end() );
636 while ( it1
!= end1
)
639 = rtl::OUStringToOString( (*it1
).first
,
640 RTL_TEXTENCODING_UTF8
);
642 = rtl::OUStringToOString( (*it1
).second
,
643 RTL_TEXTENCODING_UTF8
);
644 ne_buffer_concat( headers
, aHeader
.getStr(), ": ",
645 aValue
.getStr(), EOL
, NULL
);
653 // -------------------------------------------------------------------
655 // -------------------------------------------------------------------
656 NeonSession::NeonSession(
657 const rtl::Reference
< DAVSessionFactory
> & rSessionFactory
,
658 const rtl::OUString
& inUri
,
659 const ucbhelper::InternetProxyDecider
& rProxyDecider
)
660 throw ( DAVException
)
661 : DAVSession( rSessionFactory
),
663 m_pRequestData( new RequestDataMap
),
664 m_rProxyDecider( rProxyDecider
)
666 NeonUri
theUri( inUri
);
667 m_aScheme
= theUri
.GetScheme();
668 m_aHostName
= theUri
.GetHost();
669 m_nPort
= theUri
.GetPort();
670 m_aUserInfo
= theUri
.GetUserInfo();
675 // -------------------------------------------------------------------
677 // -------------------------------------------------------------------
678 NeonSession::~NeonSession( )
680 if ( m_pHttpSession
)
682 ne_session_destroy( m_pHttpSession
);
686 delete static_cast<RequestDataMap
*>(m_pRequestData
);
689 // -------------------------------------------------------------------
690 void NeonSession::Init()
691 throw ( DAVException
)
693 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
695 bool bCreateNewSession
= false;
697 if ( m_pHttpSession
== 0 )
699 // Ensure that Neon sockets are initialize
701 // --> tkr #151111# crashed if copy and pasted pictures from the internet
702 // ne_sock_init() was executed by two threads at the same time.
703 osl::Guard
< osl::Mutex
> theGlobalGuard( m_aGlobalMutex
);
705 if ( !m_bGlobalsInited
)
707 if ( ne_sock_init() != 0 )
708 throw DAVException( DAVException::DAV_SESSION_CREATE
,
709 NeonUri::makeConnectionEndPointString(
710 m_aHostName
, m_nPort
) );
711 #if OSL_DEBUG_LEVEL > 0
712 ne_debug_init( stderr
, NE_DBG_LOCKS
);
714 // #122205# - libxml2 needs to be initialized once if used by
715 // multithreaded programs like OOo.
717 m_bGlobalsInited
= true;
720 const ucbhelper::InternetProxyServer
& rProxyCfg
= getProxySettings();
722 m_aProxyName
= rProxyCfg
.aName
;
723 m_nProxyPort
= rProxyCfg
.nPort
;
725 // Not yet initialized. Create new session.
726 bCreateNewSession
= true;
730 // #112271# Check whether proxy settings are still valid (They may
731 // change at any time). If not, create new Neon session.
733 const ucbhelper::InternetProxyServer
& rProxyCfg
= getProxySettings();
735 if ( ( rProxyCfg
.aName
!= m_aProxyName
)
736 || ( rProxyCfg
.nPort
!= m_nProxyPort
) )
738 m_aProxyName
= rProxyCfg
.aName
;
739 m_nProxyPort
= rProxyCfg
.nPort
;
741 // new session needed, destroy old first
742 ne_session_destroy( m_pHttpSession
);
744 bCreateNewSession
= true;
748 if ( bCreateNewSession
)
750 // @@@ For FTP over HTTP proxy inUserInfo is needed to be able to
751 // build the complete request URI (including user:pass), but
752 // currently (0.22.0) neon does not allow to pass the user info
755 m_pHttpSession
= ne_session_create(
756 rtl::OUStringToOString( m_aScheme
,
757 RTL_TEXTENCODING_UTF8
).getStr(),
758 /* theUri.GetUserInfo(),
759 @@@ for FTP via HTTP proxy, but not supported by Neon */
760 rtl::OUStringToOString( m_aHostName
,
761 RTL_TEXTENCODING_UTF8
).getStr(),
764 if ( m_pHttpSession
== 0 )
765 throw DAVException( DAVException::DAV_SESSION_CREATE
,
766 NeonUri::makeConnectionEndPointString(
767 m_aHostName
, m_nPort
) );
769 if (m_aScheme
.equalsIgnoreAsciiCase( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
773 // Get all trusted certificates from key store
777 // Set a failure callback for certificate check
778 ne_ssl_set_verify( m_pHttpSession
, NeonSession_CertificationNotify
, this);
781 // Add hooks (i.e. for adding additional headers to the request)
784 /* Hook called when a request is created. */
785 //typedef void (*ne_create_request_fn)(ne_request *req, void *userdata,
786 // const char *method, const char *path);
788 ne_hook_create_request( m_pHttpSession
, create_req_hook_fn
, this );
791 /* Hook called before the request is sent. 'header' is the raw HTTP
792 * header before the trailing CRLF is added: add in more here. */
793 //typedef void (*ne_pre_send_fn)(ne_request *req, void *userdata,
794 // ne_buffer *header);
796 ne_hook_pre_send( m_pHttpSession
, NeonSession_PreSendRequest
, this );
798 /* Hook called after the request is sent. May return:
799 * NE_OK everything is okay
800 * NE_RETRY try sending the request again.
801 * anything else signifies an error, and the request is failed. The
802 * return code is passed back the _dispatch caller, so the session error
803 * must also be set appropriately (ne_set_error).
805 //typedef int (*ne_post_send_fn)(ne_request *req, void *userdata,
806 // const ne_status *status);
808 ne_hook_post_send( m_pHttpSession
, post_send_req_hook_fn
, this );
810 /* Hook called when the request is destroyed. */
811 //typedef void (*ne_destroy_req_fn)(ne_request *req, void *userdata);
813 ne_hook_destroy_request( m_pHttpSession
, destroy_req_hook_fn
, this );
815 /* Hook called when the session is destroyed. */
816 //typedef void (*ne_destroy_sess_fn)(void *userdata);
818 ne_hook_destroy_session( m_pHttpSession
, destroy_sess_hook_fn
, this );
821 if ( m_aProxyName
.getLength() )
823 ne_session_proxy( m_pHttpSession
,
824 rtl::OUStringToOString( m_aProxyName
,
825 RTL_TEXTENCODING_UTF8
)
830 if ( !s_aNeonLockStore
)
831 s_aNeonLockStore
= ne_lockstore_create();
833 if ( s_aNeonLockStore
== NULL
)
834 throw DAVException( DAVException::DAV_SESSION_CREATE
,
835 NeonUri::makeConnectionEndPointString( m_aHostName
, m_nPort
) );
837 // Register the lock store
838 ne_lockstore_register( s_aNeonLockStore
, m_pHttpSession
);
840 // Register for redirects.
841 ne_redirect_register( m_pHttpSession
);
843 // authentication callbacks.
844 #if NEON_VERSION >= 0x0260
845 ne_add_server_auth( m_pHttpSession
, NE_AUTH_ALL
, NeonSession_NeonAuth
, this );
846 ne_add_proxy_auth ( m_pHttpSession
, NE_AUTH_ALL
, NeonSession_NeonAuth
, this );
848 ne_set_server_auth( m_pHttpSession
, NeonSession_NeonAuth
, this );
849 ne_set_proxy_auth ( m_pHttpSession
, NeonSession_NeonAuth
, this );
854 // -------------------------------------------------------------------
856 sal_Bool
NeonSession::CanUse( const rtl::OUString
& inUri
)
860 NeonUri
theUri( inUri
);
861 if ( ( theUri
.GetPort() == m_nPort
) &&
862 ( theUri
.GetHost() == m_aHostName
) &&
863 ( theUri
.GetScheme() == m_aScheme
) )
866 catch ( DAVException
const & )
873 // -------------------------------------------------------------------
875 sal_Bool
NeonSession::UsesProxy()
878 return ( m_aProxyName
.getLength() > 0 );
881 // -------------------------------------------------------------------
883 // -------------------------------------------------------------------
884 void NeonSession::OPTIONS( const rtl::OUString
& inPath
,
885 DAVCapabilities
& outCapabilities
,
886 const DAVRequestEnvironment
& rEnv
)
887 throw( DAVException
)
889 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
895 HttpServerCapabilities servercaps
;
896 memset( &servercaps
, 0, sizeof( servercaps
) );
898 int theRetVal
= ne_options( m_pHttpSession
,
899 rtl::OUStringToOString(
900 inPath
, RTL_TEXTENCODING_UTF8
),
902 HandleError( theRetVal
);
904 outCapabilities
.class1
= !!servercaps
.dav_class1
;
905 outCapabilities
.class2
= !!servercaps
.dav_class2
;
906 outCapabilities
.executable
= !!servercaps
.dav_executable
;
909 // -------------------------------------------------------------------
910 // PROPFIND - allprop & named
911 // -------------------------------------------------------------------
912 void NeonSession::PROPFIND( const rtl::OUString
& inPath
,
914 const std::vector
< rtl::OUString
> & inPropNames
,
915 std::vector
< DAVResource
> & ioResources
,
916 const DAVRequestEnvironment
& rEnv
)
917 throw ( DAVException
)
919 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
925 int theRetVal
= NE_OK
;
926 NeonPropFindRequest
theRequest( m_pHttpSession
,
927 rtl::OUStringToOString(
928 inPath
, RTL_TEXTENCODING_UTF8
),
933 HandleError( theRetVal
);
936 // -------------------------------------------------------------------
937 // PROPFIND - propnames
938 // -------------------------------------------------------------------
939 void NeonSession::PROPFIND( const rtl::OUString
& inPath
,
941 std::vector
< DAVResourceInfo
>& ioResInfo
,
942 const DAVRequestEnvironment
& rEnv
)
943 throw( DAVException
)
945 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
),
958 HandleError( theRetVal
);
961 // -------------------------------------------------------------------
963 // -------------------------------------------------------------------
964 void NeonSession::PROPPATCH( const rtl::OUString
& inPath
,
965 const std::vector
< ProppatchValue
> & inValues
,
966 const DAVRequestEnvironment
& rEnv
)
967 throw( DAVException
)
969 /* @@@ Which standard live properties can be set by the client?
970 This is a known WebDAV RFC issue ( verified: 04/10/2001 )
971 --> http://www.ics.uci.edu/pub/ietf/webdav/protocol/issues.html
973 mod_dav implementation:
975 creationdate r ( File System prop )
977 getcontentlanguage r ( #ifdef DAV_DISABLE_WRITEABLE_PROPS )
978 getcontentlength r ( File System prop )
979 getcontenttype r ( #ifdef DAV_DISABLE_WRITEABLE_PROPS )
980 getetag r ( File System prop )
981 getlastmodified r ( File System prop )
986 executable w ( #ifndef WIN32 )
988 All dead properties are of course writable.
991 int theRetVal
= NE_OK
;
992 int n
; // for the "for" loop
994 // Generate the list of properties we want to set.
995 int nPropCount
= inValues
.size();
996 ne_proppatch_operation
* pItems
997 = new ne_proppatch_operation
[ nPropCount
+ 1 ];
998 for ( n
= 0; n
< nPropCount
; ++n
)
1000 const ProppatchValue
& rValue
= inValues
[ n
];
1002 // Split fullname into namespace and name!
1003 ne_propname
* pName
= new ne_propname
;
1004 DAVProperties::createNeonPropName( rValue
.name
, *pName
);
1005 pItems
[ n
].name
= pName
;
1007 if ( rValue
.operation
== PROPSET
)
1009 pItems
[ n
].type
= ne_propset
;
1011 rtl::OUString aStringValue
;
1012 if ( DAVProperties::isUCBDeadProperty( *pName
) )
1014 // DAV dead property added by WebDAV UCP?
1015 if ( !UCBDeadPropertyValue::toXML(
1016 rValue
.value
, aStringValue
) )
1019 pItems
[ n
].value
= 0;
1020 theRetVal
= NE_ERROR
;
1025 else if ( !( rValue
.value
>>= aStringValue
) )
1027 // complex properties...
1028 if ( rValue
.name
== DAVProperties::SOURCE
)
1030 uno::Sequence
< ::com::sun::star::ucb::Link
> aLinks
;
1031 if ( rValue
.value
>>= aLinks
)
1033 LinkSequence::toXML( aLinks
, aStringValue
);
1038 pItems
[ n
].value
= 0;
1039 theRetVal
= NE_ERROR
;
1046 OSL_ENSURE( sal_False
,
1047 "NeonSession::PROPPATCH - unsupported type!" );
1049 pItems
[ n
].value
= 0;
1050 theRetVal
= NE_ERROR
;
1056 = strdup( rtl::OUStringToOString( aStringValue
,
1057 RTL_TEXTENCODING_UTF8
) );
1061 pItems
[ n
].type
= ne_propremove
;
1062 pItems
[ n
].value
= 0;
1066 if ( theRetVal
== NE_OK
)
1068 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1074 pItems
[ n
].name
= 0;
1076 theRetVal
= ne_proppatch( m_pHttpSession
,
1077 rtl::OUStringToOString(
1078 inPath
, RTL_TEXTENCODING_UTF8
),
1082 for ( n
= 0; n
< nPropCount
; ++n
)
1084 free( (void *)pItems
[ n
].name
->name
);
1085 delete pItems
[ n
].name
;
1086 free( (void *)pItems
[ n
].value
);
1091 HandleError( theRetVal
);
1094 // -------------------------------------------------------------------
1096 // -------------------------------------------------------------------
1097 void NeonSession::HEAD( const ::rtl::OUString
& inPath
,
1098 const std::vector
< ::rtl::OUString
> & inHeaderNames
,
1099 DAVResource
& ioResource
,
1100 const DAVRequestEnvironment
& rEnv
)
1101 throw( DAVException
)
1103 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1109 int theRetVal
= NE_OK
;
1110 NeonHeadRequest
theRequest( m_pHttpSession
,
1115 HandleError( theRetVal
);
1118 // -------------------------------------------------------------------
1120 // -------------------------------------------------------------------
1121 uno::Reference
< io::XInputStream
>
1122 NeonSession::GET( const rtl::OUString
& inPath
,
1123 const DAVRequestEnvironment
& rEnv
)
1124 throw ( DAVException
)
1126 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1132 rtl::Reference
< NeonInputStream
> xInputStream( new NeonInputStream
);
1133 NeonRequestContext
aCtx( xInputStream
);
1134 int theRetVal
= GET( m_pHttpSession
,
1135 rtl::OUStringToOString(
1136 inPath
, RTL_TEXTENCODING_UTF8
),
1137 NeonSession_ResponseBlockReader
,
1140 HandleError( theRetVal
);
1141 return uno::Reference
< io::XInputStream
>( xInputStream
.get() );
1144 // -------------------------------------------------------------------
1146 // -------------------------------------------------------------------
1147 void NeonSession::GET( const rtl::OUString
& inPath
,
1148 uno::Reference
< io::XOutputStream
> & ioOutputStream
,
1149 const DAVRequestEnvironment
& rEnv
)
1150 throw ( DAVException
)
1152 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1158 NeonRequestContext
aCtx( ioOutputStream
);
1159 int theRetVal
= GET( m_pHttpSession
,
1160 rtl::OUStringToOString(
1161 inPath
, RTL_TEXTENCODING_UTF8
),
1162 NeonSession_ResponseBlockWriter
,
1165 HandleError( theRetVal
);
1168 // -------------------------------------------------------------------
1170 // -------------------------------------------------------------------
1171 uno::Reference
< io::XStream
>
1172 NeonSession::GET( const rtl::OUString
& inPath
,
1173 const std::vector
< ::rtl::OUString
> & inHeaderNames
,
1174 DAVResource
& ioResource
,
1175 const DAVRequestEnvironment
& rEnv
,
1176 sal_Bool bAllowEmpty
)
1177 throw ( DAVException
)
1179 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1185 ioResource
.uri
= inPath
;
1186 ioResource
.properties
.clear();
1188 rtl::Reference
< NeonInputStream
> xStream( new NeonInputStream
);
1189 NeonRequestContext
aCtx( xStream
, inHeaderNames
, ioResource
);
1190 int theRetVal
= GET( m_pHttpSession
,
1191 rtl::OUStringToOString(
1192 inPath
, RTL_TEXTENCODING_UTF8
),
1193 NeonSession_ResponseBlockReader
,
1197 HandleError( theRetVal
);
1199 catch ( DAVException
const & e
)
1201 if ( !bAllowEmpty
|| ( e
.getStatus() != SC_NOT_FOUND
) )
1204 return uno::Reference
< io::XStream
>( xStream
.get() );
1207 // -------------------------------------------------------------------
1209 // -------------------------------------------------------------------
1210 void NeonSession::GET( const rtl::OUString
& inPath
,
1211 uno::Reference
< io::XOutputStream
> & ioOutputStream
,
1212 const std::vector
< ::rtl::OUString
> & inHeaderNames
,
1213 DAVResource
& ioResource
,
1214 const DAVRequestEnvironment
& rEnv
)
1215 throw ( DAVException
)
1217 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1223 ioResource
.uri
= inPath
;
1224 ioResource
.properties
.clear();
1226 NeonRequestContext
aCtx( ioOutputStream
, inHeaderNames
, ioResource
);
1227 int theRetVal
= GET( m_pHttpSession
,
1228 rtl::OUStringToOString(
1229 inPath
, RTL_TEXTENCODING_UTF8
),
1230 NeonSession_ResponseBlockWriter
,
1233 HandleError( theRetVal
);
1236 // -------------------------------------------------------------------
1238 // -------------------------------------------------------------------
1239 void NeonSession::PUT( const rtl::OUString
& inPath
,
1240 const uno::Reference
< io::XInputStream
> & inInputStream
,
1241 const DAVRequestEnvironment
& rEnv
)
1242 throw ( DAVException
)
1244 // initialization etc. is performed in the other PUT
1246 uno::Sequence
< sal_Int8
> aDataToSend
;
1247 if ( !getDataFromInputStream( inInputStream
, aDataToSend
, false ) )
1248 throw DAVException( DAVException::DAV_INVALID_ARG
);
1251 reinterpret_cast< const char * >( aDataToSend
.getConstArray() ),
1252 aDataToSend
.getLength(),
1256 // -------------------------------------------------------------------
1258 // -------------------------------------------------------------------
1259 void NeonSession::PUT( const rtl::OUString
&inPath
,
1260 const char * buffer
,
1262 const DAVRequestEnvironment
& rEnv
)
1263 throw ( DAVException
)
1265 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1271 int theRetVal
= PUT( m_pHttpSession
,
1272 rtl::OUStringToOString(
1273 inPath
, RTL_TEXTENCODING_UTF8
),
1277 HandleError( theRetVal
);
1280 // -------------------------------------------------------------------
1282 // -------------------------------------------------------------------
1283 uno::Reference
< io::XInputStream
>
1284 NeonSession::POST( const rtl::OUString
& inPath
,
1285 const rtl::OUString
& rContentType
,
1286 const rtl::OUString
& rReferer
,
1287 const uno::Reference
< io::XInputStream
> & inInputStream
,
1288 const DAVRequestEnvironment
& rEnv
)
1289 throw ( DAVException
)
1291 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1293 uno::Sequence
< sal_Int8
> aDataToSend
;
1294 if ( !getDataFromInputStream( inInputStream
, aDataToSend
, true ) )
1295 throw DAVException( DAVException::DAV_INVALID_ARG
);
1301 rtl::Reference
< NeonInputStream
> xInputStream( new NeonInputStream
);
1302 NeonRequestContext
aCtx( xInputStream
);
1303 int theRetVal
= POST( m_pHttpSession
,
1304 rtl::OUStringToOString(
1305 inPath
, RTL_TEXTENCODING_UTF8
),
1306 reinterpret_cast< const char * >(
1307 aDataToSend
.getConstArray() ),
1308 NeonSession_ResponseBlockReader
,
1313 HandleError( theRetVal
);
1314 return uno::Reference
< io::XInputStream
>( xInputStream
.get() );
1317 // -------------------------------------------------------------------
1319 // -------------------------------------------------------------------
1320 void NeonSession::POST( const rtl::OUString
& inPath
,
1321 const rtl::OUString
& rContentType
,
1322 const rtl::OUString
& rReferer
,
1323 const uno::Reference
< io::XInputStream
> & inInputStream
,
1324 uno::Reference
< io::XOutputStream
> & oOutputStream
,
1325 const DAVRequestEnvironment
& rEnv
)
1326 throw ( DAVException
)
1328 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1330 uno::Sequence
< sal_Int8
> aDataToSend
;
1331 if ( !getDataFromInputStream( inInputStream
, aDataToSend
, true ) )
1332 throw DAVException( DAVException::DAV_INVALID_ARG
);
1338 NeonRequestContext
aCtx( oOutputStream
);
1339 int theRetVal
= POST( m_pHttpSession
,
1340 rtl::OUStringToOString(
1341 inPath
, RTL_TEXTENCODING_UTF8
),
1342 reinterpret_cast< const char * >(
1343 aDataToSend
.getConstArray() ),
1344 NeonSession_ResponseBlockWriter
,
1349 HandleError( theRetVal
);
1352 // -------------------------------------------------------------------
1354 // -------------------------------------------------------------------
1355 void NeonSession::ABORT()
1356 throw ( DAVException
)
1358 if (NULL
!=m_pHttpSession
)
1359 ne_close_connection(m_pHttpSession
);
1362 // -------------------------------------------------------------------
1364 // -------------------------------------------------------------------
1365 void NeonSession::MKCOL( const rtl::OUString
& inPath
,
1366 const DAVRequestEnvironment
& rEnv
)
1367 throw ( DAVException
)
1369 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1375 int theRetVal
= ne_mkcol( m_pHttpSession
,
1376 rtl::OUStringToOString(
1377 inPath
, RTL_TEXTENCODING_UTF8
) );
1378 HandleError( theRetVal
);
1381 // -------------------------------------------------------------------
1383 // -------------------------------------------------------------------
1384 void NeonSession::COPY( const rtl::OUString
& inSourceURL
,
1385 const rtl::OUString
& inDestinationURL
,
1386 const DAVRequestEnvironment
& rEnv
,
1387 sal_Bool inOverWrite
)
1388 throw ( DAVException
)
1390 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1396 NeonUri
theSourceUri( inSourceURL
);
1397 NeonUri
theDestinationUri( inDestinationURL
);
1399 int theRetVal
= ne_copy( m_pHttpSession
,
1400 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::MOVE( const rtl::OUString
& inSourceURL
,
1415 const rtl::OUString
& inDestinationURL
,
1416 const DAVRequestEnvironment
& rEnv
,
1417 sal_Bool inOverWrite
)
1418 throw ( DAVException
)
1420 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1426 NeonUri
theSourceUri( inSourceURL
);
1427 NeonUri
theDestinationUri( inDestinationURL
);
1428 int theRetVal
= ne_move( m_pHttpSession
,
1429 inOverWrite
? 1 : 0,
1430 rtl::OUStringToOString(
1431 theSourceUri
.GetPath(),
1432 RTL_TEXTENCODING_UTF8
),
1433 rtl::OUStringToOString(
1434 theDestinationUri
.GetPath(),
1435 RTL_TEXTENCODING_UTF8
) );
1436 HandleError( theRetVal
);
1439 // -------------------------------------------------------------------
1441 // -------------------------------------------------------------------
1442 void NeonSession::DESTROY( const rtl::OUString
& inPath
,
1443 const DAVRequestEnvironment
& rEnv
)
1444 throw ( DAVException
)
1446 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1452 int theRetVal
= ne_delete( m_pHttpSession
,
1453 rtl::OUStringToOString(
1454 inPath
, RTL_TEXTENCODING_UTF8
) );
1455 HandleError( theRetVal
);
1458 // -------------------------------------------------------------------
1460 // -------------------------------------------------------------------
1461 void NeonSession::LOCK( ucb::Lock
& rLock
,
1462 const DAVRequestEnvironment
& rEnv
)
1463 throw ( DAVException
)
1465 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1471 Lockit( rLock
, true );
1474 // -------------------------------------------------------------------
1476 // -------------------------------------------------------------------
1477 void NeonSession::UNLOCK( ucb::Lock
& rLock
,
1478 const DAVRequestEnvironment
& rEnv
)
1479 throw ( DAVException
)
1481 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1487 Lockit( rLock
, false );
1490 // -------------------------------------------------------------------
1491 const ucbhelper::InternetProxyServer
& NeonSession::getProxySettings() const
1493 if ( m_aScheme
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "http" ) ) ||
1494 m_aScheme
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "https" ) ) )
1496 return m_rProxyDecider
.getProxy( m_aScheme
,
1502 return m_rProxyDecider
.getProxy( m_aScheme
,
1503 rtl::OUString() /* not used */,
1504 -1 /* not used */ );
1508 // -------------------------------------------------------------------
1510 // Common Error Handler
1511 // -------------------------------------------------------------------
1512 void NeonSession::HandleError( int nError
)
1513 throw ( DAVException
)
1515 m_aEnv
= DAVRequestEnvironment();
1517 // Map error code to DAVException.
1524 case NE_ERROR
: // Generic error
1526 rtl::OUString aText
= rtl::OUString::createFromAscii(
1527 ne_get_error( m_pHttpSession
) );
1528 #if OSL_DEBUG_LEVEL > 0
1529 fprintf( stderr
, "WebDAV: got error '%s'\n", rtl::OUStringToOString( aText
, RTL_TEXTENCODING_UTF8
).getStr() );
1531 throw DAVException( DAVException::DAV_HTTP_ERROR
,
1533 makeStatusCode( aText
) );
1536 case NE_LOOKUP
: // Name lookup failed.
1537 throw DAVException( DAVException::DAV_HTTP_LOOKUP
,
1538 NeonUri::makeConnectionEndPointString(
1539 m_aHostName
, m_nPort
) );
1541 case NE_AUTH
: // User authentication failed on server
1542 throw DAVException( DAVException::DAV_HTTP_AUTH
,
1543 NeonUri::makeConnectionEndPointString(
1544 m_aHostName
, m_nPort
) );
1546 case NE_PROXYAUTH
: // User authentication failed on proxy
1547 throw DAVException( DAVException::DAV_HTTP_AUTHPROXY
,
1548 NeonUri::makeConnectionEndPointString(
1549 m_aProxyName
, m_nProxyPort
) );
1551 case NE_CONNECT
: // Could not connect to server
1552 throw DAVException( DAVException::DAV_HTTP_CONNECT
,
1553 NeonUri::makeConnectionEndPointString(
1554 m_aHostName
, m_nPort
) );
1556 case NE_TIMEOUT
: // Connection timed out
1557 throw DAVException( DAVException::DAV_HTTP_TIMEOUT
,
1558 NeonUri::makeConnectionEndPointString(
1559 m_aHostName
, m_nPort
) );
1561 case NE_FAILED
: // The precondition failed
1562 throw DAVException( DAVException::DAV_HTTP_FAILED
,
1563 NeonUri::makeConnectionEndPointString(
1564 m_aHostName
, m_nPort
) );
1566 case NE_RETRY
: // Retry request (ne_end_request ONLY)
1567 throw DAVException( DAVException::DAV_HTTP_RETRY
,
1568 NeonUri::makeConnectionEndPointString(
1569 m_aHostName
, m_nPort
) );
1573 NeonUri
aUri( ne_redirect_location( m_pHttpSession
) );
1575 DAVException::DAV_HTTP_REDIRECT
, aUri
.GetURI() );
1579 OSL_TRACE( "NeonSession::HandleError : Unknown Neon error code!" );
1580 throw DAVException( DAVException::DAV_HTTP_ERROR
,
1581 rtl::OUString::createFromAscii(
1582 ne_get_error( m_pHttpSession
) ) );
1587 void NeonSession::Lockit( ucb::Lock
& rLock
, bool bLockit
)
1588 throw ( DAVException
)
1590 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1592 if ( !s_aNeonLockStore
)
1593 throw DAVException( DAVException::DAV_INVALID_ARG
);
1596 ne_uri_parse( rtl::OUStringToOString( m_aEnv
.m_aRequestURI
, RTL_TEXTENCODING_UTF8
).getStr(),
1599 #if NEON_VERSION < 0x0260
1600 #define FILLIN( field, val ) aUri.field = aUri.field? aUri.field: strdup( rtl::OUStringToOString( val, RTL_TEXTENCODING_UTF8 ).getStr() )
1601 FILLIN( scheme
, m_aScheme
);
1602 FILLIN( host
, m_aHostName
);
1603 aUri
.port
= aUri
.port
? aUri
.port
: m_nPort
;
1607 // Create the neon lock
1608 NeonLock
* theLock
= ne_lockstore_findbyuri( s_aNeonLockStore
, &aUri
);
1609 bool bAlreadyExists
= false;
1611 bAlreadyExists
= true;
1614 theLock
= ne_lock_create();
1617 theLock
->uri
= aUri
;
1619 // Set the lock depth
1620 switch( rLock
.Depth
)
1622 case ucb::LockDepth_ZERO
: theLock
->depth
= NE_DEPTH_ZERO
; break;
1623 case ucb::LockDepth_ONE
: theLock
->depth
= NE_DEPTH_ONE
; break;
1624 case ucb::LockDepth_INFINITY
: theLock
->depth
= NE_DEPTH_INFINITE
; break;
1626 throw DAVException( DAVException::DAV_INVALID_ARG
);
1629 // Set the lock scope
1630 switch ( rLock
.Scope
)
1632 case ucb::LockScope_EXCLUSIVE
: theLock
->scope
= ne_lockscope_exclusive
; break;
1633 case ucb::LockScope_SHARED
: theLock
->scope
= ne_lockscope_shared
; break;
1635 throw DAVException( DAVException::DAV_INVALID_ARG
);
1639 // Set the lock owner
1640 rtl::OUString aValue
;
1641 rLock
.Owner
>>= aValue
;
1643 theLock
->owner
= strdup( rtl::OUStringToOString( aValue
, RTL_TEXTENCODING_UTF8
).getStr() );
1645 // Set the lock timeout
1646 // We re-new the lock while the stream is open
1647 theLock
->timeout
= rLock
.Timeout
;
1653 if ( bAlreadyExists
)
1655 #if NEON_VERSION >= 0x0260
1656 nRet
= ne_lock_refresh( m_pHttpSession
, theLock
);
1658 // workaround for a bug in neon 0.24
1659 // we have to call with a bigger structure that is used internally
1660 // and initialize parts of it
1664 struct ne_lock active
; /* activelock */
1665 char *token
; /* the token we're after. */
1670 struct lock_ctx ctx
;
1672 memset( &ctx
, 0, sizeof ctx
);
1673 ctx
.cdata
= ne_buffer_create();
1675 memcpy( &ctx
, theLock
, sizeof( *theLock
) );
1676 nRet
= ne_lock_refresh( m_pHttpSession
, reinterpret_cast<NeonLock
*>( &ctx
) );
1678 ne_buffer_destroy( ctx
.cdata
);
1680 if ( ( nRet
== NE_ERROR
) && strncmp (ne_get_error (m_pHttpSession
), "No activelock ", strlen ("No activelock ")) == 0 )
1682 bAlreadyExists
= false;
1683 ne_lockstore_remove( s_aNeonLockStore
, theLock
);
1686 if ( !bAlreadyExists
)
1688 nRet
= ne_lock( m_pHttpSession
, theLock
);
1690 if ( nRet
== NE_OK
)
1692 ne_lockstore_add( s_aNeonLockStore
, theLock
);
1694 uno::Sequence
< rtl::OUString
> aTokens( 1 );
1695 aTokens
[0] = rtl::OUString::createFromAscii( theLock
->token
);
1696 rLock
.LockTokens
= aTokens
;
1698 #if OSL_DEBUG_LEVEL > 0
1699 fprintf( stderr
, "WebDAV: locked the URL, the token is: %s\n", theLock
->token
);
1704 if ( ( nRet
== NE_ERROR
) && getStatusCode( m_pHttpSession
) == SC_LOCKED
)
1706 ucbhelper::cancelCommandExecution( ucb::IOErrorCode_LOCKING_VIOLATION
,
1707 uno::Sequence
< uno::Any
>( 0 ), // FIXME more info about the file?
1709 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "a locking error occured" ) ),
1710 uno::Reference
< ucb::XCommandProcessor
>() );
1712 #if OSL_DEBUG_LEVEL > 0
1713 else if ( nRet
== NE_OK
)
1714 fprintf( stderr
, "WebDAV: locked/refreshed lock OK\n" );
1716 fprintf( stderr
, "WebDAV: failed to lock the file: %s\n", ne_get_error( m_pHttpSession
) );
1721 // Set the lock token
1722 if ( rLock
.LockTokens
.getLength() > 0 )
1724 rtl::OUString theToken
= rLock
.LockTokens
.getConstArray()[ 0 ];
1725 theLock
->token
= strdup( rtl::OUStringToOString( theToken
, RTL_TEXTENCODING_UTF8
).getStr() );
1727 #if OSL_DEBUG_LEVEL > 0
1728 fprintf( stderr
, "WebDAV: going to unlock the URL, the token is: %s\n", theLock
->token
);
1731 ne_unlock( m_pHttpSession
, theLock
);
1732 ne_lockstore_remove( s_aNeonLockStore
, theLock
);
1733 // FIXME even ne_lock_destroy( theLock )?
1738 // -------------------------------------------------------------------
1741 void runResponseHeaderHandler( void * userdata
,
1742 const char * value
)
1744 rtl::OUString
aHeader( rtl::OUString::createFromAscii( value
) );
1745 sal_Int32 nPos
= aHeader
.indexOf( ':' );
1749 rtl::OUString
aHeaderName( aHeader
.copy( 0, nPos
) );
1751 NeonRequestContext
* pCtx
1752 = static_cast< NeonRequestContext
* >( userdata
);
1754 // Note: Empty vector means that all headers are requested.
1755 bool bIncludeIt
= ( pCtx
->pHeaderNames
->size() == 0 );
1759 // Check whether this header was requested.
1760 std::vector
< ::rtl::OUString
>::const_iterator
it(
1761 pCtx
->pHeaderNames
->begin() );
1762 const std::vector
< ::rtl::OUString
>::const_iterator
end(
1763 pCtx
->pHeaderNames
->end() );
1767 // header names are case insensitive
1768 if ( (*it
).equalsIgnoreAsciiCase( aHeaderName
) )
1770 aHeaderName
= (*it
);
1782 // Create & set the PropertyValue
1783 DAVPropertyValue thePropertyValue
;
1784 thePropertyValue
.IsCaseSensitive
= false;
1785 thePropertyValue
.Name
= aHeaderName
;
1787 if ( nPos
< aHeader
.getLength() )
1788 thePropertyValue
.Value
<<= aHeader
.copy( nPos
+ 1 ).trim();
1790 // Add the newly created PropertyValue
1791 pCtx
->pResource
->properties
.push_back( thePropertyValue
);
1798 // -------------------------------------------------------------------
1800 int NeonSession::GET( ne_session
* sess
,
1802 ne_block_reader reader
,
1806 //struct get_context ctx;
1807 ne_request
* req
= ne_request_create( sess
, "GET", uri
);
1809 void *cursor
= NULL
;
1810 const char *name
, *value
;
1812 #if NEON_VERSION < 0x0250
1814 ne_add_response_header_catcher( req
, runResponseHeaderHandler
, userdata
);
1816 ne_add_response_body_reader( req
, ne_accept_2xx
, reader
, userdata
);
1818 ret
= ne_request_dispatch( req
);
1820 #if NEON_VERSION >= 0x0250
1823 while ((cursor
= ne_response_header_iterate(req
, cursor
, &name
, &value
))
1828 ne_snprintf(buffer
, sizeof buffer
, "%s: %s", name
, value
);
1830 runResponseHeaderHandler(userdata
, buffer
);
1834 if ( ret
== NE_OK
&& ne_get_status( req
)->klass
!= 2 )
1837 ne_request_destroy( req
);
1841 // -------------------------------------------------------------------
1843 int NeonSession::PUT( ne_session
* sess
,
1845 const char * buffer
,
1848 ne_request
* req
= ne_request_create( sess
, "PUT", uri
);
1851 ne_lock_using_resource( req
, uri
, 0 );
1852 ne_lock_using_parent( req
, uri
);
1854 ne_set_request_body_buffer( req
, buffer
, size
);
1856 ret
= ne_request_dispatch( req
);
1858 if ( ret
== NE_OK
&& ne_get_status( req
)->klass
!= 2 )
1861 ne_request_destroy( req
);
1865 // -------------------------------------------------------------------
1866 int NeonSession::POST( ne_session
* sess
,
1868 const char * buffer
,
1869 ne_block_reader reader
,
1871 const rtl::OUString
& rContentType
,
1872 const rtl::OUString
& rReferer
)
1874 ne_request
* req
= ne_request_create( sess
, "POST", uri
);
1875 //struct get_context ctx;
1878 RequestDataMap
* pData
= 0;
1880 if ( rContentType
.getLength() || rReferer
.getLength() )
1882 // Remember contenttype and referer. Data will be added to HTTP request
1883 // header in in 'PreSendRequest' callback.
1884 pData
= static_cast< RequestDataMap
* >( m_pRequestData
);
1885 (*pData
)[ req
] = RequestData( rContentType
, rReferer
);
1891 //ctx.session = sess;
1893 ///* Read the value of the Content-Length header into ctx.total */
1894 //ne_add_response_header_handler( req, "Content-Length",
1895 // ne_handle_numeric_header, &ctx.total );
1897 ne_add_response_body_reader( req
, ne_accept_2xx
, reader
, userdata
);
1899 ne_set_request_body_buffer( req
, buffer
, strlen( buffer
) );
1901 ret
= ne_request_dispatch( req
);
1906 if ( ret
== NE_OK
&& ne_get_status( req
)->klass
!= 2 )
1909 ne_request_destroy( req
);
1913 // Remove request data from session's list.
1914 RequestDataMap::iterator it
= pData
->find( req
);
1915 if ( it
!= pData
->end() )
1922 // -------------------------------------------------------------------
1924 bool NeonSession::getDataFromInputStream(
1925 const uno::Reference
< io::XInputStream
> & xStream
,
1926 uno::Sequence
< sal_Int8
> & rData
,
1927 bool bAppendTrailingZeroByte
)
1931 uno::Reference
< io::XSeekable
> xSeekable( xStream
, uno::UNO_QUERY
);
1932 if ( xSeekable
.is() )
1937 = sal::static_int_cast
<sal_Int32
>(xSeekable
->getLength());
1939 = xStream
->readBytes( rData
, nSize
);
1941 if ( nRead
== nSize
)
1943 if ( bAppendTrailingZeroByte
)
1945 rData
.realloc( nSize
+ 1 );
1946 rData
[ nSize
] = sal_Int8( 0 );
1951 catch ( io::NotConnectedException
const & )
1955 catch ( io::BufferSizeExceededException
const & )
1959 catch ( io::IOException
const & )
1961 // getLength, readBytes
1968 uno::Sequence
< sal_Int8
> aBuffer
;
1971 sal_Int32 nRead
= xStream
->readSomeBytes( aBuffer
, 65536 );
1974 if ( rData
.getLength() < ( nPos
+ nRead
) )
1975 rData
.realloc( nPos
+ nRead
);
1977 aBuffer
.realloc( nRead
);
1978 rtl_copyMemory( (void*)( rData
.getArray() + nPos
),
1979 (const void*)aBuffer
.getConstArray(),
1983 aBuffer
.realloc( 0 );
1984 nRead
= xStream
->readSomeBytes( aBuffer
, 65536 );
1987 if ( bAppendTrailingZeroByte
)
1989 rData
.realloc( nPos
+ 1 );
1990 rData
[ nPos
] = sal_Int8( 0 );
1994 catch ( io::NotConnectedException
const & )
1998 catch ( io::BufferSizeExceededException
const & )
2002 catch ( io::IOException
const & )
2010 // -------------------------------------------------------------------
2013 NeonSession::Map
NeonSession::certMap
;
2015 // ---------------------------------------------------------------------
2017 NeonSession::isDomainMatch( rtl::OUString certHostName
)
2019 rtl::OUString hostName
= getHostName();
2021 if (hostName
.equalsIgnoreAsciiCase( certHostName
))
2026 if ( 0 == certHostName
.indexOf( rtl::OUString::createFromAscii( "*" ) ) && hostName
.getLength() >= certHostName
.getLength() )
2028 rtl::OUString cmpStr
= certHostName
.copy( 1 );
2030 if ( hostName
.matchIgnoreAsciiCase( cmpStr
, hostName
.getLength( ) - cmpStr
.getLength()) )