1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include <unordered_map>
33 #include "osl/diagnose.h"
35 #include <rtl/string.h>
36 #include <ne_socket.h>
38 #include <ne_redirect.h>
41 // old neon versions forgot to set this
43 #include <ne_compress.h>
46 #include "libxml/parser.h"
47 #include "rtl/ustrbuf.hxx"
48 #include "comphelper/processfactory.hxx"
49 #include "comphelper/sequence.hxx"
50 #include <comphelper/stl_types.hxx>
51 #include "ucbhelper/simplecertificatevalidationrequest.hxx"
53 #include "DAVAuthListener.hxx"
54 #include "NeonTypes.hxx"
55 #include "NeonSession.hxx"
56 #include "NeonInputStream.hxx"
57 #include "NeonPropFindRequest.hxx"
58 #include "NeonHeadRequest.hxx"
59 #include "NeonUri.hxx"
60 #include "LinkSequence.hxx"
61 #include "UCBDeadPropertyValue.hxx"
63 #include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
64 #include <com/sun/star/security/XCertificate.hpp>
65 #include <com/sun/star/security/CertificateValidity.hpp>
66 #include <com/sun/star/security/CertificateContainerStatus.hpp>
67 #include <com/sun/star/security/CertificateContainer.hpp>
68 #include <com/sun/star/security/XCertificateContainer.hpp>
69 #include <com/sun/star/ucb/Lock.hpp>
70 #include <com/sun/star/beans/NamedValue.hpp>
71 #include <com/sun/star/xml/crypto/SEInitializer.hpp>
73 #include <boost/bind.hpp>
75 using namespace com::sun::star
;
76 using namespace webdav_ucp
;
85 OUString aContentType
;
89 RequestData( const OUString
& rContentType
,
90 const OUString
& rReferer
)
91 : aContentType( rContentType
), aReferer( rReferer
) {}
96 bool operator()( const ne_request
* p1
, const ne_request
* p2
) const
104 size_t operator()( const ne_request
* p
) const
106 return reinterpret_cast<size_t>(p
);
110 typedef std::unordered_map
119 static sal_uInt16
makeStatusCode( const OUString
& rStatusText
)
121 // Extract status code from session error string. Unfortunately
122 // neon provides no direct access to the status code...
124 if ( rStatusText
.getLength() < 3 )
127 "makeStatusCode - status text string to short!" );
131 sal_Int32 nPos
= rStatusText
.indexOf( ' ' );
134 OSL_FAIL( "makeStatusCode - wrong status text format!" );
138 return sal_uInt16( rStatusText
.copy( 0, nPos
).toInt32() );
141 static bool noKeepAlive( const uno::Sequence
< beans::NamedValue
>& rFlags
)
143 if ( !rFlags
.hasElements() )
146 // find "KeepAlive" property
147 const beans::NamedValue
* pAry(rFlags
.getConstArray());
148 const sal_Int32
nLen(rFlags
.getLength());
149 const beans::NamedValue
* pValue(
150 std::find_if(pAry
,pAry
+nLen
,
151 boost::bind(comphelper::TNamedValueEqualFunctor(),
153 OUString("KeepAlive"))));
154 if ( pValue
!= pAry
+nLen
&& !pValue
->Value
.get
<sal_Bool
>() )
160 struct NeonRequestContext
162 uno::Reference
< io::XOutputStream
> xOutputStream
;
163 rtl::Reference
< NeonInputStream
> xInputStream
;
164 const std::vector
< OUString
> * pHeaderNames
;
165 DAVResource
* pResource
;
167 NeonRequestContext( uno::Reference
< io::XOutputStream
> & xOutStrm
)
168 : xOutputStream( xOutStrm
), xInputStream( 0 ),
169 pHeaderNames( 0 ), pResource( 0 ) {}
171 NeonRequestContext( const rtl::Reference
< NeonInputStream
> & xInStrm
)
172 : xOutputStream( 0 ), xInputStream( xInStrm
),
173 pHeaderNames( 0 ), pResource( 0 ) {}
175 NeonRequestContext( uno::Reference
< io::XOutputStream
> & xOutStrm
,
176 const std::vector
< OUString
> & inHeaderNames
,
177 DAVResource
& ioResource
)
178 : xOutputStream( xOutStrm
), xInputStream( 0 ),
179 pHeaderNames( &inHeaderNames
), pResource( &ioResource
) {}
181 NeonRequestContext( const rtl::Reference
< NeonInputStream
> & xInStrm
,
182 const std::vector
< OUString
> & inHeaderNames
,
183 DAVResource
& ioResource
)
184 : xOutputStream( 0 ), xInputStream( xInStrm
),
185 pHeaderNames( &inHeaderNames
), pResource( &ioResource
) {}
188 // A simple Neon response_block_reader for use with an XInputStream
189 extern "C" int NeonSession_ResponseBlockReader(void * inUserData
,
193 // neon sometimes calls this function with (inLen == 0)...
196 NeonRequestContext
* pCtx
197 = static_cast< NeonRequestContext
* >( inUserData
);
199 rtl::Reference
< NeonInputStream
> xInputStream(
200 pCtx
->xInputStream
);
202 if ( xInputStream
.is() )
203 xInputStream
->AddToStream( inBuf
, inLen
);
208 // A simple Neon response_block_reader for use with an XOutputStream
209 extern "C" int NeonSession_ResponseBlockWriter( void * inUserData
,
213 // neon calls this function with (inLen == 0)...
216 NeonRequestContext
* pCtx
217 = static_cast< NeonRequestContext
* >( inUserData
);
218 uno::Reference
< io::XOutputStream
> xOutputStream
219 = pCtx
->xOutputStream
;
221 if ( xOutputStream
.is() )
223 const uno::Sequence
< sal_Int8
> aSeq( reinterpret_cast<sal_Int8
const *>(inBuf
), inLen
);
224 xOutputStream
->writeBytes( aSeq
);
230 extern "C" int NeonSession_NeonAuth( void * inUserData
,
231 #if defined NE_FEATURE_SSPI && ! defined SYSTEM_NEON
232 const char * inAuthProtocol
,
234 const char * inRealm
,
236 char * inoutUserName
,
237 char * inoutPassWord
)
239 /* The callback used to request the username and password in the given
240 * realm. The username and password must be copied into the buffers
241 * which are both of size NE_ABUFSIZ. The 'attempt' parameter is zero
242 * on the first call to the callback, and increases by one each time
243 * an attempt to authenticate fails.
245 * The callback must return zero to indicate that authentication
246 * should be attempted with the username/password, or non-zero to
247 * cancel the request. (if non-zero, username and password are
250 NeonSession
* theSession
= static_cast< NeonSession
* >( inUserData
);
251 DAVAuthListener
* pListener
252 = theSession
->getRequestEnvironment().m_xAuthListener
.get();
258 OUString theUserName
;
259 OUString thePassWord
;
263 // neon does not handle username supplied with request URI (for
264 // instance when doing FTP over proxy - last checked: 0.23.5 )
268 NeonUri
uri( theSession
->getRequestEnvironment().m_aRequestURI
);
269 OUString
aUserInfo( uri
.GetUserInfo() );
270 if ( !aUserInfo
.isEmpty() )
272 sal_Int32 nPos
= aUserInfo
.indexOf( '@' );
275 theUserName
= aUserInfo
;
279 theUserName
= aUserInfo
.copy( 0, nPos
);
280 thePassWord
= aUserInfo
.copy( nPos
+ 1 );
284 catch ( DAVException
const & )
292 // username buffer is prefilled with user name from last attempt.
293 theUserName
= OUString::createFromAscii( inoutUserName
);
294 // @@@ Neon does not initialize password buffer (last checked: 0.22.0).
295 //thePassWord = OUString::createFromAscii( inoutPassWord );
298 bool bCanUseSystemCreds
= false;
300 #if defined NE_FEATURE_SSPI && ! defined SYSTEM_NEON
302 = (attempt
== 0) && // avoid endless loops
303 ne_has_support( NE_FEATURE_SSPI
) && // Windows-only feature.
304 ( ( ne_strcasecmp( inAuthProtocol
, "NTLM" ) == 0 ) ||
305 ( ne_strcasecmp( inAuthProtocol
, "Negotiate" ) == 0 ) );
308 int theRetVal
= pListener
->authenticate(
309 OUString::createFromAscii( inRealm
),
310 theSession
->getHostName(),
316 OUStringToOString( theUserName
, RTL_TEXTENCODING_UTF8
) );
317 if ( aUser
.getLength() > ( NE_ABUFSIZ
- 1 ) )
320 "NeonSession_NeonAuth - username to long!" );
325 OUStringToOString( thePassWord
, RTL_TEXTENCODING_UTF8
) );
326 if ( aPass
.getLength() > ( NE_ABUFSIZ
- 1 ) )
329 "NeonSession_NeonAuth - password to long!" );
333 strcpy( inoutUserName
, // #100211# - checked
334 OUStringToOString( theUserName
, RTL_TEXTENCODING_UTF8
).getStr() );
336 strcpy( inoutPassWord
, // #100211# - checked
337 OUStringToOString( thePassWord
, RTL_TEXTENCODING_UTF8
).getStr() );
343 OUString
GetHostnamePart( const OUString
& _rRawString
)
346 OUString
sPartId("CN=");
347 sal_Int32 nContStart
= _rRawString
.indexOf( sPartId
);
348 if ( nContStart
!= -1 )
350 nContStart
+= sPartId
.getLength();
351 sal_Int32 nContEnd
= _rRawString
.indexOf( ',', nContStart
);
352 sPart
= nContEnd
!= -1 ?
353 _rRawString
.copy(nContStart
, nContEnd
- nContStart
) :
354 _rRawString
.copy(nContStart
);
360 extern "C" int NeonSession_CertificationNotify( void *userdata
,
362 const ne_ssl_certificate
*cert
)
366 NeonSession
* pSession
= static_cast< NeonSession
* >( userdata
);
367 uno::Reference
< security::XCertificateContainer
> xCertificateContainer
;
370 xCertificateContainer
= security::CertificateContainer::create( pSession
->getComponentContext() );
372 catch ( uno::Exception
const & )
376 if ( !xCertificateContainer
.is() )
381 char * dn
= ne_ssl_readable_dname( ne_ssl_cert_subject( cert
) );
382 OUString
cert_subject( dn
, strlen( dn
), RTL_TEXTENCODING_UTF8
, 0 );
386 security::CertificateContainerStatus
certificateContainer(
387 xCertificateContainer
->hasCertificate(
388 pSession
->getHostName(), cert_subject
) );
390 if ( certificateContainer
!= security::CertificateContainerStatus_NOCERT
)
392 certificateContainer
== security::CertificateContainerStatus_TRUSTED
396 uno::Reference
< xml::crypto::XSEInitializer
> xSEInitializer
;
399 xSEInitializer
= xml::crypto::SEInitializer::create( pSession
->getComponentContext() );
401 catch ( uno::Exception
const & )
405 if ( !xSEInitializer
.is() )
408 uno::Reference
< xml::crypto::XXMLSecurityContext
> xSecurityContext(
409 xSEInitializer
->createSecurityContext( OUString() ) );
411 uno::Reference
< xml::crypto::XSecurityEnvironment
> xSecurityEnv(
412 xSecurityContext
->getSecurityEnvironment() );
414 //The end entity certificate
415 char * eeCertB64
= ne_ssl_cert_export( cert
);
417 OString
sEECertB64( eeCertB64
);
419 uno::Reference
< security::XCertificate
> xEECert(
420 xSecurityEnv
->createCertificateFromAscii(
421 OStringToOUString( sEECertB64
, RTL_TEXTENCODING_ASCII_US
) ) );
423 ne_free( eeCertB64
);
426 std::vector
< uno::Reference
< security::XCertificate
> > vecCerts
;
427 const ne_ssl_certificate
* issuerCert
= cert
;
430 //get the intermediate certificate
431 //the returned value is const ! Therfore it does not need to be freed
432 //with ne_ssl_cert_free, which takes a non-const argument
433 issuerCert
= ne_ssl_cert_signedby( issuerCert
);
434 if ( NULL
== issuerCert
)
437 char * imCertB64
= ne_ssl_cert_export( issuerCert
);
438 OString
sInterMediateCertB64( imCertB64
);
439 ne_free( imCertB64
);
441 uno::Reference
< security::XCertificate
> xImCert(
442 xSecurityEnv
->createCertificateFromAscii(
443 OStringToOUString( sInterMediateCertB64
, RTL_TEXTENCODING_ASCII_US
) ) );
445 vecCerts
.push_back( xImCert
);
449 sal_Int64 certValidity
= xSecurityEnv
->verifyCertificate( xEECert
,
450 ::comphelper::containerToSequence( vecCerts
) );
452 if ( pSession
->isDomainMatch(
453 GetHostnamePart( xEECert
.get()->getSubjectName() ) ) )
455 // if host name matched with certificate then look if the
456 // certificate was ok
457 if( certValidity
== security::CertificateValidity::VALID
)
461 const uno::Reference
< ucb::XCommandEnvironment
> xEnv(
462 pSession
->getRequestEnvironment().m_xEnv
);
465 failures
= static_cast< int >( certValidity
);
467 uno::Reference
< task::XInteractionHandler
> xIH(
468 xEnv
->getInteractionHandler() );
471 rtl::Reference
< ucbhelper::SimpleCertificateValidationRequest
>
472 xRequest( new ucbhelper::SimpleCertificateValidationRequest(
473 (sal_Int32
)failures
, xEECert
, pSession
->getHostName() ) );
474 xIH
->handle( xRequest
.get() );
476 rtl::Reference
< ucbhelper::InteractionContinuation
> xSelection
477 = xRequest
->getSelection();
479 if ( xSelection
.is() )
481 uno::Reference
< task::XInteractionApprove
> xApprove(
482 xSelection
.get(), uno::UNO_QUERY
);
485 xCertificateContainer
->addCertificate(
486 pSession
->getHostName(), cert_subject
, sal_True
);
492 xCertificateContainer
->addCertificate(
493 pSession
->getHostName(), cert_subject
, sal_False
);
501 xCertificateContainer
->addCertificate(
502 pSession
->getHostName(), cert_subject
, sal_False
);
509 extern "C" void NeonSession_PreSendRequest( ne_request
* req
,
511 ne_buffer
* headers
)
513 // userdata -> value returned by 'create'
515 NeonSession
* pSession
= static_cast< NeonSession
* >( userdata
);
518 // If there is a proxy server in between, it shall never use
519 // cached data. We always want 'up-to-date' data.
520 ne_buffer_concat( headers
, "Pragma: no-cache", EOL
, NULL
);
521 // alternative, but understoud by HTTP 1.1 servers only:
522 // ne_buffer_concat( headers, "Cache-Control: max-age=0", EOL, NULL );
524 const RequestDataMap
* pRequestData
525 = static_cast< const RequestDataMap
* >(
526 pSession
->getRequestData() );
528 RequestDataMap::const_iterator it
= pRequestData
->find( req
);
529 if ( it
!= pRequestData
->end() )
531 if ( !(*it
).second
.aContentType
.isEmpty() )
533 char * pData
= headers
->data
;
534 if ( strstr( pData
, "Content-Type:" ) == NULL
)
537 = OUStringToOString( (*it
).second
.aContentType
,
538 RTL_TEXTENCODING_UTF8
);
539 ne_buffer_concat( headers
, "Content-Type: ",
540 aType
.getStr(), EOL
, NULL
);
544 if ( !(*it
).second
.aReferer
.isEmpty() )
546 char * pData
= headers
->data
;
547 if ( strstr( pData
, "Referer:" ) == NULL
)
550 = OUStringToOString( (*it
).second
.aReferer
,
551 RTL_TEXTENCODING_UTF8
);
552 ne_buffer_concat( headers
, "Referer: ",
553 aReferer
.getStr(), EOL
, NULL
);
558 const DAVRequestHeaders
& rHeaders
559 = pSession
->getRequestEnvironment().m_aRequestHeaders
;
561 DAVRequestHeaders::const_iterator
it1( rHeaders
.begin() );
562 const DAVRequestHeaders::const_iterator
end1( rHeaders
.end() );
564 while ( it1
!= end1
)
567 = OUStringToOString( (*it1
).first
,
568 RTL_TEXTENCODING_UTF8
);
570 = OUStringToOString( (*it1
).second
,
571 RTL_TEXTENCODING_UTF8
);
572 ne_buffer_concat( headers
, aHeader
.getStr(), ": ",
573 aValue
.getStr(), EOL
, NULL
);
581 bool NeonSession::m_bGlobalsInited
= false;
582 //See https://bugzilla.redhat.com/show_bug.cgi?id=544619#c4
583 //neon is threadsafe, but uses gnutls which is only thread-safe
584 //if initialized to be thread-safe. cups, unfortunately, generally
585 //initializes it first, and as non-thread-safe, leaving the entire
587 osl::Mutex aGlobalNeonMutex
;
588 NeonLockStore
NeonSession::m_aNeonLockStore
;
590 NeonSession::NeonSession( const rtl::Reference
< DAVSessionFactory
> & rSessionFactory
,
591 const OUString
& inUri
,
592 const uno::Sequence
< beans::NamedValue
>& rFlags
,
593 const ucbhelper::InternetProxyDecider
& rProxyDecider
)
594 throw ( std::exception
)
595 : DAVSession( rSessionFactory
)
598 , m_pHttpSession( 0 )
599 , m_pRequestData( new RequestDataMap
)
600 , m_rProxyDecider( rProxyDecider
)
602 NeonUri
theUri( inUri
);
603 m_aScheme
= theUri
.GetScheme();
604 m_aHostName
= theUri
.GetHost();
605 m_nPort
= theUri
.GetPort();
608 NeonSession::~NeonSession( )
610 if ( m_pHttpSession
)
613 osl::Guard
< osl::Mutex
> theGlobalGuard( aGlobalNeonMutex
);
614 ne_session_destroy( m_pHttpSession
);
618 delete static_cast< RequestDataMap
* >( m_pRequestData
);
621 void NeonSession::Init( const DAVRequestEnvironment
& rEnv
)
622 throw (css::uno::RuntimeException
, std::exception
)
624 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
629 void NeonSession::Init()
630 throw (css::uno::RuntimeException
, std::exception
)
632 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
634 bool bCreateNewSession
= false;
636 if ( m_pHttpSession
== 0 )
638 // Ensure that Neon sockets are initialized
639 osl::Guard
< osl::Mutex
> theGlobalGuard( aGlobalNeonMutex
);
640 if ( !m_bGlobalsInited
)
642 if ( ne_sock_init() != 0 )
643 throw DAVException( DAVException::DAV_SESSION_CREATE
,
644 NeonUri::makeConnectionEndPointString(
645 m_aHostName
, m_nPort
) );
647 // #122205# - libxml2 needs to be initialized once if used by
648 // multithreaded programs like OOo.
650 #if OSL_DEBUG_LEVEL > 0
651 // for more debug flags see ne_utils.h; NE_DEBUGGING must be defined
652 // while compiling neon in order to actually activate neon debug
654 ne_debug_init( stderr
, NE_DBG_FLUSH
664 m_bGlobalsInited
= true;
667 const ucbhelper::InternetProxyServer
& rProxyCfg
= getProxySettings();
669 m_aProxyName
= rProxyCfg
.aName
;
670 m_nProxyPort
= rProxyCfg
.nPort
;
672 // Not yet initialized. Create new session.
673 bCreateNewSession
= true;
677 // #112271# Check whether proxy settings are still valid (They may
678 // change at any time). If not, create new Neon session.
680 const ucbhelper::InternetProxyServer
& rProxyCfg
= getProxySettings();
682 if ( ( rProxyCfg
.aName
!= m_aProxyName
)
683 || ( rProxyCfg
.nPort
!= m_nProxyPort
) )
685 m_aProxyName
= rProxyCfg
.aName
;
686 m_nProxyPort
= rProxyCfg
.nPort
;
688 // new session needed, destroy old first
690 osl::Guard
< osl::Mutex
> theGlobalGuard( aGlobalNeonMutex
);
691 ne_session_destroy( m_pHttpSession
);
694 bCreateNewSession
= true;
698 if ( bCreateNewSession
)
700 // @@@ For FTP over HTTP proxy inUserInfo is needed to be able to
701 // build the complete request URI (including user:pass), but
702 // currently (0.22.0) neon does not allow to pass the user info
706 osl::Guard
< osl::Mutex
> theGlobalGuard( aGlobalNeonMutex
);
707 m_pHttpSession
= ne_session_create(
708 OUStringToOString( m_aScheme
, RTL_TEXTENCODING_UTF8
).getStr(),
709 /* theUri.GetUserInfo(),
710 @@@ for FTP via HTTP proxy, but not supported by Neon */
711 OUStringToOString( m_aHostName
, RTL_TEXTENCODING_UTF8
).getStr(),
715 if ( m_pHttpSession
== 0 )
716 throw DAVException( DAVException::DAV_SESSION_CREATE
,
717 NeonUri::makeConnectionEndPointString(
718 m_aHostName
, m_nPort
) );
720 // Register the session with the lock store
721 m_aNeonLockStore
.registerSession( m_pHttpSession
);
723 if ( m_aScheme
.equalsIgnoreAsciiCase(
724 OUString( "https" ) ) )
726 // Set a failure callback for certificate check
728 m_pHttpSession
, NeonSession_CertificationNotify
, this);
730 // Tell Neon to tell the SSL library used (OpenSSL or
731 // GnuTLS, I guess) to use a default set of root
733 ne_ssl_trust_default_ca(m_pHttpSession
);
736 // Add hooks (i.e. for adding additional headers to the request)
739 /* Hook called when a request is created. */
740 //typedef void (*ne_create_request_fn)(ne_request *req, void *userdata,
741 // const char *method, const char *path);
743 ne_hook_create_request( m_pHttpSession
, create_req_hook_fn
, this );
746 /* Hook called before the request is sent. 'header' is the raw HTTP
747 * header before the trailing CRLF is added: add in more here. */
748 //typedef void (*ne_pre_send_fn)(ne_request *req, void *userdata,
749 // ne_buffer *header);
751 ne_hook_pre_send( m_pHttpSession
, NeonSession_PreSendRequest
, this );
753 /* Hook called after the request is sent. May return:
754 * NE_OK everything is okay
755 * NE_RETRY try sending the request again.
756 * anything else signifies an error, and the request is failed. The
757 * return code is passed back the _dispatch caller, so the session error
758 * must also be set appropriately (ne_set_error).
760 //typedef int (*ne_post_send_fn)(ne_request *req, void *userdata,
761 // const ne_status *status);
763 ne_hook_post_send( m_pHttpSession
, post_send_req_hook_fn
, this );
765 /* Hook called when the request is destroyed. */
766 //typedef void (*ne_destroy_req_fn)(ne_request *req, void *userdata);
768 ne_hook_destroy_request( m_pHttpSession
, destroy_req_hook_fn
, this );
770 /* Hook called when the session is destroyed. */
771 //typedef void (*ne_destroy_sess_fn)(void *userdata);
773 ne_hook_destroy_session( m_pHttpSession
, destroy_sess_hook_fn
, this );
776 if ( !m_aProxyName
.isEmpty() )
778 ne_session_proxy( m_pHttpSession
,
781 RTL_TEXTENCODING_UTF8
).getStr(),
786 if ( noKeepAlive(m_aFlags
) )
787 ne_set_session_flag( m_pHttpSession
, NE_SESSFLAG_PERSIST
, 0 );
789 // Register for redirects.
790 ne_redirect_register( m_pHttpSession
);
792 // authentication callbacks.
794 ne_add_server_auth( m_pHttpSession
, NE_AUTH_ALL
, NeonSession_NeonAuth
, this );
795 ne_add_proxy_auth ( m_pHttpSession
, NE_AUTH_ALL
, NeonSession_NeonAuth
, this );
797 ne_set_server_auth( m_pHttpSession
, NeonSession_NeonAuth
, this );
798 ne_set_proxy_auth ( m_pHttpSession
, NeonSession_NeonAuth
, this );
803 bool NeonSession::CanUse( const OUString
& inUri
,
804 const uno::Sequence
< beans::NamedValue
>& rFlags
)
808 NeonUri
theUri( inUri
);
809 if ( ( theUri
.GetPort() == m_nPort
) &&
810 ( theUri
.GetHost() == m_aHostName
) &&
811 ( theUri
.GetScheme() == m_aScheme
) &&
812 ( rFlags
== m_aFlags
) )
815 catch ( DAVException
const & )
822 bool NeonSession::UsesProxy()
825 return !m_aProxyName
.isEmpty() ;
828 void NeonSession::OPTIONS( const OUString
& inPath
,
829 DAVCapabilities
& outCapabilities
,
830 const DAVRequestEnvironment
& rEnv
)
831 throw( std::exception
)
833 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
837 HttpServerCapabilities servercaps
;
838 memset( &servercaps
, 0, sizeof( servercaps
) );
840 int theRetVal
= ne_options( m_pHttpSession
,
842 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
845 HandleError( theRetVal
, inPath
, rEnv
);
847 outCapabilities
.class1
= !!servercaps
.dav_class1
;
848 outCapabilities
.class2
= !!servercaps
.dav_class2
;
849 outCapabilities
.executable
= !!servercaps
.dav_executable
;
852 void NeonSession::PROPFIND( const OUString
& inPath
,
854 const std::vector
< OUString
> & inPropNames
,
855 std::vector
< DAVResource
> & ioResources
,
856 const DAVRequestEnvironment
& rEnv
)
857 throw ( std::exception
)
859 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
863 int theRetVal
= NE_OK
;
864 NeonPropFindRequest
theRequest( m_pHttpSession
,
866 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
872 HandleError( theRetVal
, inPath
, rEnv
);
875 void NeonSession::PROPFIND( const OUString
& inPath
,
877 std::vector
< DAVResourceInfo
> & ioResInfo
,
878 const DAVRequestEnvironment
& rEnv
)
879 throw( std::exception
)
881 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
885 int theRetVal
= NE_OK
;
886 NeonPropFindRequest
theRequest( m_pHttpSession
,
888 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
893 HandleError( theRetVal
, inPath
, rEnv
);
896 void NeonSession::PROPPATCH( const OUString
& inPath
,
897 const std::vector
< ProppatchValue
> & inValues
,
898 const DAVRequestEnvironment
& rEnv
)
899 throw( std::exception
)
901 /* @@@ Which standard live properties can be set by the client?
902 This is a known WebDAV RFC issue ( verified: 04/10/2001 )
903 --> http://www.ics.uci.edu/pub/ietf/webdav/protocol/issues.html
905 mod_dav implementation:
907 creationdate r ( File System prop )
909 getcontentlanguage r ( #ifdef DAV_DISABLE_WRITEABLE_PROPS )
910 getcontentlength r ( File System prop )
911 getcontenttype r ( #ifdef DAV_DISABLE_WRITEABLE_PROPS )
912 getetag r ( File System prop )
913 getlastmodified r ( File System prop )
918 executable w ( #ifndef WIN32 )
920 All dead properties are of course writable.
923 int theRetVal
= NE_OK
;
925 int n
; // for the "for" loop
927 // Generate the list of properties we want to set.
928 int nPropCount
= inValues
.size();
929 ne_proppatch_operation
* pItems
930 = new ne_proppatch_operation
[ nPropCount
+ 1 ];
931 for ( n
= 0; n
< nPropCount
; ++n
)
933 const ProppatchValue
& rValue
= inValues
[ n
];
935 // Split fullname into namespace and name!
936 ne_propname
* pName
= new ne_propname
;
937 DAVProperties::createNeonPropName( rValue
.name
, *pName
);
938 pItems
[ n
].name
= pName
;
940 if ( rValue
.operation
== PROPSET
)
942 pItems
[ n
].type
= ne_propset
;
944 OUString aStringValue
;
945 if ( DAVProperties::isUCBDeadProperty( *pName
) )
947 // DAV dead property added by WebDAV UCP?
948 if ( !UCBDeadPropertyValue::toXML( rValue
.value
,
952 pItems
[ n
].value
= 0;
953 theRetVal
= NE_ERROR
;
958 else if ( !( rValue
.value
>>= aStringValue
) )
960 // complex properties...
961 if ( rValue
.name
== DAVProperties::SOURCE
)
963 uno::Sequence
< ucb::Link
> aLinks
;
964 if ( rValue
.value
>>= aLinks
)
966 LinkSequence::toXML( aLinks
, aStringValue
);
971 pItems
[ n
].value
= 0;
972 theRetVal
= NE_ERROR
;
979 OSL_FAIL( "NeonSession::PROPPATCH - unsupported type!" );
981 pItems
[ n
].value
= 0;
982 theRetVal
= NE_ERROR
;
988 = strdup( OUStringToOString( aStringValue
,
989 RTL_TEXTENCODING_UTF8
).getStr() );
993 pItems
[ n
].type
= ne_propremove
;
994 pItems
[ n
].value
= 0;
998 if ( theRetVal
== NE_OK
)
1000 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1004 pItems
[ n
].name
= 0;
1006 theRetVal
= ne_proppatch( m_pHttpSession
,
1008 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1012 for ( n
= 0; n
< nPropCount
; ++n
)
1014 free( (void *)pItems
[ n
].name
->name
);
1015 delete pItems
[ n
].name
;
1016 free( (void *)pItems
[ n
].value
);
1021 HandleError( theRetVal
, inPath
, rEnv
);
1024 void NeonSession::HEAD( const OUString
& inPath
,
1025 const std::vector
< OUString
> & inHeaderNames
,
1026 DAVResource
& ioResource
,
1027 const DAVRequestEnvironment
& rEnv
)
1028 throw( std::exception
)
1030 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1034 int theRetVal
= NE_OK
;
1035 NeonHeadRequest
theRequest( m_pHttpSession
,
1041 HandleError( theRetVal
, inPath
, rEnv
);
1044 uno::Reference
< io::XInputStream
>
1045 NeonSession::GET( const OUString
& inPath
,
1046 const DAVRequestEnvironment
& rEnv
)
1047 throw ( std::exception
)
1049 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1053 rtl::Reference
< NeonInputStream
> xInputStream( new NeonInputStream
);
1054 NeonRequestContext
aCtx( xInputStream
);
1055 int theRetVal
= GET( m_pHttpSession
,
1057 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1058 NeonSession_ResponseBlockReader
,
1062 HandleError( theRetVal
, inPath
, rEnv
);
1064 return uno::Reference
< io::XInputStream
>( xInputStream
.get() );
1067 void NeonSession::GET( const OUString
& inPath
,
1068 uno::Reference
< io::XOutputStream
> & ioOutputStream
,
1069 const DAVRequestEnvironment
& rEnv
)
1070 throw ( std::exception
)
1072 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1076 NeonRequestContext
aCtx( ioOutputStream
);
1077 int theRetVal
= GET( m_pHttpSession
,
1079 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1080 NeonSession_ResponseBlockWriter
,
1084 HandleError( theRetVal
, inPath
, rEnv
);
1087 uno::Reference
< io::XInputStream
>
1088 NeonSession::GET( const OUString
& inPath
,
1089 const std::vector
< OUString
> & inHeaderNames
,
1090 DAVResource
& ioResource
,
1091 const DAVRequestEnvironment
& rEnv
)
1092 throw ( std::exception
)
1094 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1098 ioResource
.uri
= inPath
;
1099 ioResource
.properties
.clear();
1101 rtl::Reference
< NeonInputStream
> xInputStream( new NeonInputStream
);
1102 NeonRequestContext
aCtx( xInputStream
, inHeaderNames
, ioResource
);
1103 int theRetVal
= GET( m_pHttpSession
,
1105 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1106 NeonSession_ResponseBlockReader
,
1110 HandleError( theRetVal
, inPath
, rEnv
);
1112 return uno::Reference
< io::XInputStream
>( xInputStream
.get() );
1115 void NeonSession::GET( const OUString
& inPath
,
1116 uno::Reference
< io::XOutputStream
> & ioOutputStream
,
1117 const std::vector
< OUString
> & inHeaderNames
,
1118 DAVResource
& ioResource
,
1119 const DAVRequestEnvironment
& rEnv
)
1120 throw ( std::exception
)
1122 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1126 ioResource
.uri
= inPath
;
1127 ioResource
.properties
.clear();
1129 NeonRequestContext
aCtx( ioOutputStream
, inHeaderNames
, ioResource
);
1130 int theRetVal
= GET( m_pHttpSession
,
1132 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1133 NeonSession_ResponseBlockWriter
,
1137 HandleError( theRetVal
, inPath
, rEnv
);
1140 void NeonSession::PUT( const OUString
& inPath
,
1141 const uno::Reference
< io::XInputStream
> & inInputStream
,
1142 const DAVRequestEnvironment
& rEnv
)
1143 throw ( std::exception
)
1145 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1147 uno::Sequence
< sal_Int8
> aDataToSend
;
1148 if ( !getDataFromInputStream( inInputStream
, aDataToSend
, false ) )
1149 throw DAVException( DAVException::DAV_INVALID_ARG
);
1153 int theRetVal
= PUT( m_pHttpSession
,
1155 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1156 reinterpret_cast< const char * >(
1157 aDataToSend
.getConstArray() ),
1158 aDataToSend
.getLength() );
1160 HandleError( theRetVal
, inPath
, rEnv
);
1163 uno::Reference
< io::XInputStream
>
1164 NeonSession::POST( const OUString
& inPath
,
1165 const OUString
& rContentType
,
1166 const OUString
& rReferer
,
1167 const uno::Reference
< io::XInputStream
> & inInputStream
,
1168 const DAVRequestEnvironment
& rEnv
)
1169 throw ( std::exception
)
1171 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1173 uno::Sequence
< sal_Int8
> aDataToSend
;
1174 if ( !getDataFromInputStream( inInputStream
, aDataToSend
, true ) )
1175 throw DAVException( DAVException::DAV_INVALID_ARG
);
1179 rtl::Reference
< NeonInputStream
> xInputStream( new NeonInputStream
);
1180 NeonRequestContext
aCtx( xInputStream
);
1181 int theRetVal
= POST( m_pHttpSession
,
1183 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1184 reinterpret_cast< const char * >(
1185 aDataToSend
.getConstArray() ),
1186 NeonSession_ResponseBlockReader
,
1191 HandleError( theRetVal
, inPath
, rEnv
);
1193 return uno::Reference
< io::XInputStream
>( xInputStream
.get() );
1196 void NeonSession::POST( const OUString
& inPath
,
1197 const OUString
& rContentType
,
1198 const OUString
& rReferer
,
1199 const uno::Reference
< io::XInputStream
> & inInputStream
,
1200 uno::Reference
< io::XOutputStream
> & oOutputStream
,
1201 const DAVRequestEnvironment
& rEnv
)
1202 throw ( std::exception
)
1204 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1206 uno::Sequence
< sal_Int8
> aDataToSend
;
1207 if ( !getDataFromInputStream( inInputStream
, aDataToSend
, true ) )
1208 throw DAVException( DAVException::DAV_INVALID_ARG
);
1212 NeonRequestContext
aCtx( oOutputStream
);
1213 int theRetVal
= POST( m_pHttpSession
,
1215 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1216 reinterpret_cast< const char * >(
1217 aDataToSend
.getConstArray() ),
1218 NeonSession_ResponseBlockWriter
,
1223 HandleError( theRetVal
, inPath
, rEnv
);
1226 void NeonSession::MKCOL( const OUString
& inPath
,
1227 const DAVRequestEnvironment
& rEnv
)
1228 throw ( std::exception
)
1230 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1234 int theRetVal
= ne_mkcol( m_pHttpSession
,
1236 inPath
, RTL_TEXTENCODING_UTF8
).getStr() );
1238 HandleError( theRetVal
, inPath
, rEnv
);
1241 void NeonSession::COPY( const OUString
& inSourceURL
,
1242 const OUString
& inDestinationURL
,
1243 const DAVRequestEnvironment
& rEnv
,
1245 throw ( std::exception
)
1247 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1251 NeonUri
theSourceUri( inSourceURL
);
1252 NeonUri
theDestinationUri( inDestinationURL
);
1254 int theRetVal
= ne_copy( m_pHttpSession
,
1255 inOverWrite
? 1 : 0,
1258 theSourceUri
.GetPath(),
1259 RTL_TEXTENCODING_UTF8
).getStr(),
1261 theDestinationUri
.GetPath(),
1262 RTL_TEXTENCODING_UTF8
).getStr() );
1264 HandleError( theRetVal
, inSourceURL
, rEnv
);
1267 void NeonSession::MOVE( const OUString
& inSourceURL
,
1268 const OUString
& inDestinationURL
,
1269 const DAVRequestEnvironment
& rEnv
,
1271 throw ( std::exception
)
1273 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1277 NeonUri
theSourceUri( inSourceURL
);
1278 NeonUri
theDestinationUri( inDestinationURL
);
1279 int theRetVal
= ne_move( m_pHttpSession
,
1280 inOverWrite
? 1 : 0,
1282 theSourceUri
.GetPath(),
1283 RTL_TEXTENCODING_UTF8
).getStr(),
1285 theDestinationUri
.GetPath(),
1286 RTL_TEXTENCODING_UTF8
).getStr() );
1288 HandleError( theRetVal
, inSourceURL
, rEnv
);
1291 void NeonSession::DESTROY( const OUString
& inPath
,
1292 const DAVRequestEnvironment
& rEnv
)
1293 throw ( std::exception
)
1295 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1299 int theRetVal
= ne_delete( m_pHttpSession
,
1301 inPath
, RTL_TEXTENCODING_UTF8
).getStr() );
1303 HandleError( theRetVal
, inPath
, rEnv
);
1308 sal_Int32
lastChanceToSendRefreshRequest( TimeValue
const & rStart
,
1312 osl_getSystemTime( &aEnd
);
1314 // Try to estimate a safe absolute time for sending the
1315 // lock refresh request.
1316 sal_Int32 lastChanceToSendRefreshRequest
= -1;
1317 if ( timeout
!= NE_TIMEOUT_INFINITE
)
1319 sal_Int32 calltime
= aEnd
.Seconds
- rStart
.Seconds
;
1320 if ( calltime
<= timeout
)
1322 lastChanceToSendRefreshRequest
1323 = aEnd
.Seconds
+ timeout
- calltime
;
1327 OSL_TRACE( "No chance to refresh lock before timeout!" );
1330 return lastChanceToSendRefreshRequest
;
1336 void NeonSession::LOCK( const OUString
& inPath
,
1338 const DAVRequestEnvironment
& rEnv
)
1339 throw ( std::exception
)
1341 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1345 /* Create a depth zero, exclusive write lock, with default timeout
1346 * (allowing a server to pick a default). token, owner and uri are
1348 NeonLock
* theLock
= ne_lock_create();
1352 ne_uri_parse( OUStringToOString( makeAbsoluteURL( inPath
),
1353 RTL_TEXTENCODING_UTF8
).getStr(),
1355 theLock
->uri
= aUri
;
1357 // Set the lock depth
1358 switch( rLock
.Depth
)
1360 case ucb::LockDepth_ZERO
:
1361 theLock
->depth
= NE_DEPTH_ZERO
;
1363 case ucb::LockDepth_ONE
:
1364 theLock
->depth
= NE_DEPTH_ONE
;
1366 case ucb::LockDepth_INFINITY
:
1367 theLock
->depth
= NE_DEPTH_INFINITE
;
1370 throw DAVException( DAVException::DAV_INVALID_ARG
);
1373 // Set the lock scope
1374 switch ( rLock
.Scope
)
1376 case ucb::LockScope_EXCLUSIVE
:
1377 theLock
->scope
= ne_lockscope_exclusive
;
1379 case ucb::LockScope_SHARED
:
1380 theLock
->scope
= ne_lockscope_shared
;
1383 throw DAVException( DAVException::DAV_INVALID_ARG
);
1386 // Set the lock timeout
1387 theLock
->timeout
= (long)rLock
.Timeout
;
1389 // Set the lock owner
1391 rLock
.Owner
>>= aValue
;
1393 ne_strdup( OUStringToOString( aValue
,
1394 RTL_TEXTENCODING_UTF8
).getStr() );
1395 TimeValue startCall
;
1396 osl_getSystemTime( &startCall
);
1398 int theRetVal
= ne_lock( m_pHttpSession
, theLock
);
1400 if ( theRetVal
== NE_OK
)
1402 m_aNeonLockStore
.addLock( theLock
,
1404 lastChanceToSendRefreshRequest(
1405 startCall
, theLock
->timeout
) );
1407 uno::Sequence
< OUString
> aTokens( 1 );
1408 aTokens
[ 0 ] = OUString::createFromAscii( theLock
->token
);
1409 rLock
.LockTokens
= aTokens
;
1411 OSL_TRACE( "NeonSession::LOCK: created lock for %s. token: %s",
1412 OUStringToOString( makeAbsoluteURL( inPath
),
1413 RTL_TEXTENCODING_UTF8
).getStr(),
1418 ne_lock_destroy( theLock
);
1420 OSL_TRACE( "NeonSession::LOCK: obtaining lock for %s failed!",
1421 OUStringToOString( makeAbsoluteURL( inPath
),
1422 RTL_TEXTENCODING_UTF8
).getStr() );
1425 HandleError( theRetVal
, inPath
, rEnv
);
1428 // Refresh existing lock
1429 sal_Int64
NeonSession::LOCK( const OUString
& inPath
,
1431 const DAVRequestEnvironment
& rEnv
)
1432 throw ( std::exception
)
1434 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1436 // Try to get the neon lock from lock store
1438 = m_aNeonLockStore
.findByUri( makeAbsoluteURL( inPath
) );
1440 throw DAVException( DAVException::DAV_NOT_LOCKED
);
1444 // refresh existing lock.
1445 theLock
->timeout
= static_cast< long >( nTimeout
);
1447 TimeValue startCall
;
1448 osl_getSystemTime( &startCall
);
1450 int theRetVal
= ne_lock_refresh( m_pHttpSession
, theLock
);
1452 if ( theRetVal
== NE_OK
)
1454 m_aNeonLockStore
.updateLock( theLock
,
1455 lastChanceToSendRefreshRequest(
1456 startCall
, theLock
->timeout
) );
1459 HandleError( theRetVal
, inPath
, rEnv
);
1461 return theLock
->timeout
;
1464 // Refresh existing lock
1465 bool NeonSession::LOCK( NeonLock
* pLock
,
1466 sal_Int32
& rlastChanceToSendRefreshRequest
)
1468 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1470 #if OSL_DEBUG_LEVEL > 0
1471 char * p
= ne_uri_unparse( &(pLock
->uri
) );
1472 OSL_TRACE( "NeonSession::LOCK: Refreshing lock for %s.", p
);
1476 // refresh existing lock.
1478 TimeValue startCall
;
1479 osl_getSystemTime( &startCall
);
1481 if ( ne_lock_refresh( m_pHttpSession
, pLock
) == NE_OK
)
1483 rlastChanceToSendRefreshRequest
1484 = lastChanceToSendRefreshRequest( startCall
, pLock
->timeout
);
1486 OSL_TRACE( "Lock successfully refreshed." );
1491 OSL_TRACE( "Lock not refreshed!" );
1496 void NeonSession::UNLOCK( const OUString
& inPath
,
1497 const DAVRequestEnvironment
& rEnv
)
1498 throw ( std::exception
)
1500 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1502 // get the neon lock from lock store
1504 = m_aNeonLockStore
.findByUri( makeAbsoluteURL( inPath
) );
1506 throw DAVException( DAVException::DAV_NOT_LOCKED
);
1510 int theRetVal
= ne_unlock( m_pHttpSession
, theLock
);
1512 if ( theRetVal
== NE_OK
)
1514 m_aNeonLockStore
.removeLock( theLock
);
1515 ne_lock_destroy( theLock
);
1519 OSL_TRACE( "NeonSession::UNLOCK: unlocking of %s failed.",
1520 OUStringToOString( makeAbsoluteURL( inPath
),
1521 RTL_TEXTENCODING_UTF8
).getStr() );
1524 HandleError( theRetVal
, inPath
, rEnv
);
1527 bool NeonSession::UNLOCK( NeonLock
* pLock
)
1529 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1531 #if OSL_DEBUG_LEVEL > 0
1532 char * p
= ne_uri_unparse( &(pLock
->uri
) );
1533 OSL_TRACE( "NeonSession::UNLOCK: Unlocking %s.", p
);
1537 if ( ne_unlock( m_pHttpSession
, pLock
) == NE_OK
)
1539 OSL_TRACE( "UNLOCK succeeded." );
1544 OSL_TRACE( "UNLOCK failed!" );
1549 void NeonSession::abort()
1550 throw ( std::exception
)
1552 SAL_INFO("ucb.ucp.webdav", "neon commands cannot be aborted");
1555 const ucbhelper::InternetProxyServer
& NeonSession::getProxySettings() const
1557 if ( m_aScheme
== "http" || m_aScheme
== "https" )
1559 return m_rProxyDecider
.getProxy( m_aScheme
,
1565 return m_rProxyDecider
.getProxy( m_aScheme
,
1566 OUString() /* not used */,
1567 -1 /* not used */ );
1573 bool containsLocktoken( const uno::Sequence
< ucb::Lock
> & rLocks
,
1574 const char * token
)
1576 for ( sal_Int32 n
= 0; n
< rLocks
.getLength(); ++n
)
1578 const uno::Sequence
< OUString
> & rTokens
1579 = rLocks
[ n
].LockTokens
;
1580 for ( sal_Int32 m
= 0; m
< rTokens
.getLength(); ++m
)
1582 if ( rTokens
[ m
].equalsAscii( token
) )
1591 bool NeonSession::removeExpiredLocktoken( const OUString
& inURL
,
1592 const DAVRequestEnvironment
& rEnv
)
1594 NeonLock
* theLock
= m_aNeonLockStore
.findByUri( inURL
);
1598 // do a lockdiscovery to check whether this lock is still valid.
1601 // @@@ Alternative: use ne_lock_discover() => less overhead
1603 std::vector
< DAVResource
> aResources
;
1604 std::vector
< OUString
> aPropNames
;
1605 aPropNames
.push_back( DAVProperties::LOCKDISCOVERY
);
1607 PROPFIND( rEnv
.m_aRequestURI
, DAVZERO
, aPropNames
, aResources
, rEnv
);
1609 if ( aResources
.empty() )
1612 std::vector
< DAVPropertyValue
>::const_iterator it
1613 = aResources
[ 0 ].properties
.begin();
1614 std::vector
< DAVPropertyValue
>::const_iterator end
1615 = aResources
[ 0 ].properties
.end();
1619 if ( (*it
).Name
.equals( DAVProperties::LOCKDISCOVERY
) )
1621 uno::Sequence
< ucb::Lock
> aLocks
;
1622 if ( !( (*it
).Value
>>= aLocks
) )
1625 if ( !containsLocktoken( aLocks
, theLock
->token
) )
1637 // No lockdiscovery prop in propfind result / locktoken not found
1638 // in propfind result -> not locked
1639 OSL_TRACE( "NeonSession::removeExpiredLocktoken: Removing "
1640 " expired lock token for %s. token: %s",
1641 OUStringToOString( inURL
,
1642 RTL_TEXTENCODING_UTF8
).getStr(),
1645 m_aNeonLockStore
.removeLock( theLock
);
1646 ne_lock_destroy( theLock
);
1649 catch ( DAVException
const & )
1655 // Common error handler
1656 void NeonSession::HandleError( int nError
,
1657 const OUString
& inPath
,
1658 const DAVRequestEnvironment
& rEnv
)
1659 throw ( std::exception
)
1661 m_aEnv
= DAVRequestEnvironment();
1663 // Map error code to DAVException.
1669 case NE_ERROR
: // Generic error
1671 OUString aText
= OUString::createFromAscii(
1672 ne_get_error( m_pHttpSession
) );
1674 sal_uInt16 code
= makeStatusCode( aText
);
1676 if ( code
== SC_LOCKED
)
1678 if ( m_aNeonLockStore
.findByUri(
1679 makeAbsoluteURL( inPath
) ) == 0 )
1681 // locked by 3rd party
1682 throw DAVException( DAVException::DAV_LOCKED
);
1686 // locked by ourself
1687 throw DAVException( DAVException::DAV_LOCKED_SELF
);
1691 // Special handling for 400 and 412 status codes, which may indicate
1692 // that a lock previously obtained by us has been released meanwhile
1693 // by the server. Unfortunately, RFC is not clear at this point,
1694 // thus server implementations behave different...
1695 else if ( code
== SC_BAD_REQUEST
|| code
== SC_PRECONDITION_FAILED
)
1697 if ( removeExpiredLocktoken( makeAbsoluteURL( inPath
), rEnv
) )
1698 throw DAVException( DAVException::DAV_LOCK_EXPIRED
);
1701 throw DAVException( DAVException::DAV_HTTP_ERROR
, aText
, code
);
1703 case NE_LOOKUP
: // Name lookup failed.
1704 throw DAVException( DAVException::DAV_HTTP_LOOKUP
,
1705 NeonUri::makeConnectionEndPointString(
1706 m_aHostName
, m_nPort
) );
1708 case NE_AUTH
: // User authentication failed on server
1709 throw DAVException( DAVException::DAV_HTTP_AUTH
,
1710 NeonUri::makeConnectionEndPointString(
1711 m_aHostName
, m_nPort
) );
1713 case NE_PROXYAUTH
: // User authentication failed on proxy
1714 throw DAVException( DAVException::DAV_HTTP_AUTHPROXY
,
1715 NeonUri::makeConnectionEndPointString(
1716 m_aProxyName
, m_nProxyPort
) );
1718 case NE_CONNECT
: // Could not connect to server
1719 throw DAVException( DAVException::DAV_HTTP_CONNECT
,
1720 NeonUri::makeConnectionEndPointString(
1721 m_aHostName
, m_nPort
) );
1723 case NE_TIMEOUT
: // Connection timed out
1724 throw DAVException( DAVException::DAV_HTTP_TIMEOUT
,
1725 NeonUri::makeConnectionEndPointString(
1726 m_aHostName
, m_nPort
) );
1728 case NE_FAILED
: // The precondition failed
1729 throw DAVException( DAVException::DAV_HTTP_FAILED
,
1730 NeonUri::makeConnectionEndPointString(
1731 m_aHostName
, m_nPort
) );
1733 case NE_RETRY
: // Retry request (ne_end_request ONLY)
1734 throw DAVException( DAVException::DAV_HTTP_RETRY
,
1735 NeonUri::makeConnectionEndPointString(
1736 m_aHostName
, m_nPort
) );
1740 NeonUri
aUri( ne_redirect_location( m_pHttpSession
) );
1742 DAVException::DAV_HTTP_REDIRECT
, aUri
.GetURI() );
1746 OSL_TRACE( "NeonSession::HandleError : Unknown Neon error code!" );
1747 throw DAVException( DAVException::DAV_HTTP_ERROR
,
1748 OUString::createFromAscii(
1749 ne_get_error( m_pHttpSession
) ) );
1756 void runResponseHeaderHandler( void * userdata
,
1757 const char * value
)
1759 OUString
aHeader( OUString::createFromAscii( value
) );
1760 sal_Int32 nPos
= aHeader
.indexOf( ':' );
1764 OUString
aHeaderName( aHeader
.copy( 0, nPos
) );
1766 NeonRequestContext
* pCtx
1767 = static_cast< NeonRequestContext
* >( userdata
);
1769 // Note: Empty vector means that all headers are requested.
1770 bool bIncludeIt
= ( pCtx
->pHeaderNames
->empty() );
1774 // Check whether this header was requested.
1775 std::vector
< OUString
>::const_iterator
it(
1776 pCtx
->pHeaderNames
->begin() );
1777 const std::vector
< OUString
>::const_iterator
end(
1778 pCtx
->pHeaderNames
->end() );
1782 // header names are case insensitive
1783 if ( (*it
).equalsIgnoreAsciiCase( aHeaderName
) )
1785 aHeaderName
= (*it
);
1797 // Create & set the PropertyValue
1798 DAVPropertyValue thePropertyValue
;
1799 thePropertyValue
.IsCaseSensitive
= false;
1800 thePropertyValue
.Name
= aHeaderName
;
1802 if ( nPos
< aHeader
.getLength() )
1803 thePropertyValue
.Value
<<= aHeader
.copy( nPos
+ 1 ).trim();
1805 // Add the newly created PropertyValue
1806 pCtx
->pResource
->properties
.push_back( thePropertyValue
);
1813 int NeonSession::GET( ne_session
* sess
,
1815 ne_block_reader reader
,
1819 //struct get_context ctx;
1820 ne_request
* req
= ne_request_create( sess
, "GET", uri
);
1824 = ne_decompress_reader( req
, ne_accept_2xx
, reader
, userdata
);
1827 osl::Guard
< osl::Mutex
> theGlobalGuard( aGlobalNeonMutex
);
1828 ret
= ne_request_dispatch( req
);
1833 void *cursor
= NULL
;
1834 const char *name
, *value
;
1835 while ( ( cursor
= ne_response_header_iterate(
1836 req
, cursor
, &name
, &value
) ) != NULL
)
1840 ne_snprintf(buffer
, sizeof buffer
, "%s: %s", name
, value
);
1841 runResponseHeaderHandler(userdata
, buffer
);
1845 if ( ret
== NE_OK
&& ne_get_status( req
)->klass
!= 2 )
1849 ne_decompress_destroy(dc
);
1851 ne_request_destroy( req
);
1855 int NeonSession::PUT( ne_session
* sess
,
1857 const char * buffer
,
1860 ne_request
* req
= ne_request_create( sess
, "PUT", uri
);
1863 ne_lock_using_resource( req
, uri
, 0 );
1864 ne_lock_using_parent( req
, uri
);
1866 ne_set_request_body_buffer( req
, buffer
, size
);
1869 osl::Guard
< osl::Mutex
> theGlobalGuard( aGlobalNeonMutex
);
1870 ret
= ne_request_dispatch( req
);
1873 if ( ret
== NE_OK
&& ne_get_status( req
)->klass
!= 2 )
1876 ne_request_destroy( req
);
1880 int NeonSession::POST( ne_session
* sess
,
1882 const char * buffer
,
1883 ne_block_reader reader
,
1885 const OUString
& rContentType
,
1886 const OUString
& rReferer
)
1888 ne_request
* req
= ne_request_create( sess
, "POST", uri
);
1889 //struct get_context ctx;
1892 RequestDataMap
* pData
= 0;
1894 if ( !rContentType
.isEmpty() || !rReferer
.isEmpty() )
1896 // Remember contenttype and referer. Data will be added to HTTP request
1897 // header in 'PreSendRequest' callback.
1898 pData
= static_cast< RequestDataMap
* >( m_pRequestData
);
1899 (*pData
)[ req
] = RequestData( rContentType
, rReferer
);
1905 //ctx.session = sess;
1907 ///* Read the value of the Content-Length header into ctx.total */
1908 //ne_add_response_header_handler( req, "Content-Length",
1909 // ne_handle_numeric_header, &ctx.total );
1911 ne_add_response_body_reader( req
, ne_accept_2xx
, reader
, userdata
);
1913 ne_set_request_body_buffer( req
, buffer
, strlen( buffer
) );
1916 osl::Guard
< osl::Mutex
> theGlobalGuard( aGlobalNeonMutex
);
1917 ret
= ne_request_dispatch( req
);
1923 if ( ret
== NE_OK
&& ne_get_status( req
)->klass
!= 2 )
1926 ne_request_destroy( req
);
1930 // Remove request data from session's list.
1931 RequestDataMap::iterator it
= pData
->find( req
);
1932 if ( it
!= pData
->end() )
1940 NeonSession::getDataFromInputStream(
1941 const uno::Reference
< io::XInputStream
> & xStream
,
1942 uno::Sequence
< sal_Int8
> & rData
,
1943 bool bAppendTrailingZeroByte
)
1947 uno::Reference
< io::XSeekable
> xSeekable( xStream
, uno::UNO_QUERY
);
1948 if ( xSeekable
.is() )
1953 = sal::static_int_cast
<sal_Int32
>(xSeekable
->getLength());
1955 = xStream
->readBytes( rData
, nSize
);
1957 if ( nRead
== nSize
)
1959 if ( bAppendTrailingZeroByte
)
1961 rData
.realloc( nSize
+ 1 );
1962 rData
[ nSize
] = sal_Int8( 0 );
1967 catch ( io::NotConnectedException
const & )
1971 catch ( io::BufferSizeExceededException
const & )
1975 catch ( io::IOException
const & )
1977 // getLength, readBytes
1984 uno::Sequence
< sal_Int8
> aBuffer
;
1987 sal_Int32 nRead
= xStream
->readSomeBytes( aBuffer
, 65536 );
1990 if ( rData
.getLength() < ( nPos
+ nRead
) )
1991 rData
.realloc( nPos
+ nRead
);
1993 aBuffer
.realloc( nRead
);
1994 memcpy( (void*)( rData
.getArray() + nPos
),
1995 (const void*)aBuffer
.getConstArray(),
1999 aBuffer
.realloc( 0 );
2000 nRead
= xStream
->readSomeBytes( aBuffer
, 65536 );
2003 if ( bAppendTrailingZeroByte
)
2005 rData
.realloc( nPos
+ 1 );
2006 rData
[ nPos
] = sal_Int8( 0 );
2010 catch ( io::NotConnectedException
const & )
2014 catch ( io::BufferSizeExceededException
const & )
2018 catch ( io::IOException
const & )
2028 NeonSession::isDomainMatch( const OUString
& certHostName
)
2030 OUString hostName
= getHostName();
2032 if (hostName
.equalsIgnoreAsciiCase( certHostName
) )
2035 if ( certHostName
.startsWith( "*" ) &&
2036 hostName
.getLength() >= certHostName
.getLength() )
2038 OUString cmpStr
= certHostName
.copy( 1 );
2040 if ( hostName
.matchIgnoreAsciiCase(
2041 cmpStr
, hostName
.getLength() - cmpStr
.getLength() ) )
2047 OUString
NeonSession::makeAbsoluteURL( OUString
const & rURL
) const
2051 // Is URL relative or already absolute?
2052 if ( !rURL
.isEmpty() && rURL
[ 0 ] != '/' )
2055 return OUString( rURL
);
2060 memset( &aUri
, 0, sizeof( aUri
) );
2062 ne_fill_server_uri( m_pHttpSession
, &aUri
);
2064 = ne_strdup( OUStringToOString(
2065 rURL
, RTL_TEXTENCODING_UTF8
).getStr() );
2066 NeonUri
aNeonUri( &aUri
);
2067 ne_uri_free( &aUri
);
2068 return aNeonUri
.GetURI();
2071 catch ( DAVException
const & )
2078 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */