1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include <boost/unordered_map.hpp>
33 #include "osl/diagnose.h"
35 #include <rtl/string.h>
36 #include <ne_socket.h>
38 #include <ne_redirect.h>
41 // 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
110 typedef boost::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( (sal_Int8
*)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
= _rRawString
.copy( nContStart
, nContEnd
- nContStart
);
358 extern "C" int NeonSession_CertificationNotify( void *userdata
,
360 const ne_ssl_certificate
*cert
)
364 NeonSession
* pSession
= static_cast< NeonSession
* >( userdata
);
365 uno::Reference
< security::XCertificateContainer
> xCertificateContainer
;
368 xCertificateContainer
= security::CertificateContainer::create( pSession
->getComponentContext() );
370 catch ( uno::Exception
const & )
374 if ( !xCertificateContainer
.is() )
379 char * dn
= ne_ssl_readable_dname( ne_ssl_cert_subject( cert
) );
380 OUString
cert_subject( dn
, strlen( dn
), RTL_TEXTENCODING_UTF8
, 0 );
384 security::CertificateContainerStatus
certificateContainer(
385 xCertificateContainer
->hasCertificate(
386 pSession
->getHostName(), cert_subject
) );
388 if ( certificateContainer
!= security::CertificateContainerStatus_NOCERT
)
390 certificateContainer
== security::CertificateContainerStatus_TRUSTED
394 uno::Reference
< xml::crypto::XSEInitializer
> xSEInitializer
;
397 xSEInitializer
= xml::crypto::SEInitializer::create( pSession
->getComponentContext() );
399 catch ( uno::Exception
const & )
403 if ( !xSEInitializer
.is() )
406 uno::Reference
< xml::crypto::XXMLSecurityContext
> xSecurityContext(
407 xSEInitializer
->createSecurityContext( OUString() ) );
409 uno::Reference
< xml::crypto::XSecurityEnvironment
> xSecurityEnv(
410 xSecurityContext
->getSecurityEnvironment() );
412 //The end entity certificate
413 char * eeCertB64
= ne_ssl_cert_export( cert
);
415 OString
sEECertB64( eeCertB64
);
417 uno::Reference
< security::XCertificate
> xEECert(
418 xSecurityEnv
->createCertificateFromAscii(
419 OStringToOUString( sEECertB64
, RTL_TEXTENCODING_ASCII_US
) ) );
421 ne_free( eeCertB64
);
424 std::vector
< uno::Reference
< security::XCertificate
> > vecCerts
;
425 const ne_ssl_certificate
* issuerCert
= cert
;
428 //get the intermediate certificate
429 //the returned value is const ! Therfore it does not need to be freed
430 //with ne_ssl_cert_free, which takes a non-const argument
431 issuerCert
= ne_ssl_cert_signedby( issuerCert
);
432 if ( NULL
== issuerCert
)
435 char * imCertB64
= ne_ssl_cert_export( issuerCert
);
436 OString
sInterMediateCertB64( imCertB64
);
437 ne_free( imCertB64
);
439 uno::Reference
< security::XCertificate
> xImCert(
440 xSecurityEnv
->createCertificateFromAscii(
441 OStringToOUString( sInterMediateCertB64
, RTL_TEXTENCODING_ASCII_US
) ) );
443 vecCerts
.push_back( xImCert
);
447 sal_Int64 certValidity
= xSecurityEnv
->verifyCertificate( xEECert
,
448 ::comphelper::containerToSequence( vecCerts
) );
450 if ( pSession
->isDomainMatch(
451 GetHostnamePart( xEECert
.get()->getSubjectName() ) ) )
453 // if host name matched with certificate then look if the
454 // certificate was ok
455 if( certValidity
== security::CertificateValidity::VALID
)
459 const uno::Reference
< ucb::XCommandEnvironment
> xEnv(
460 pSession
->getRequestEnvironment().m_xEnv
);
463 failures
= static_cast< int >( certValidity
);
465 uno::Reference
< task::XInteractionHandler
> xIH(
466 xEnv
->getInteractionHandler() );
469 rtl::Reference
< ucbhelper::SimpleCertificateValidationRequest
>
470 xRequest( new ucbhelper::SimpleCertificateValidationRequest(
471 (sal_Int32
)failures
, xEECert
, pSession
->getHostName() ) );
472 xIH
->handle( xRequest
.get() );
474 rtl::Reference
< ucbhelper::InteractionContinuation
> xSelection
475 = xRequest
->getSelection();
477 if ( xSelection
.is() )
479 uno::Reference
< task::XInteractionApprove
> xApprove(
480 xSelection
.get(), uno::UNO_QUERY
);
483 xCertificateContainer
->addCertificate(
484 pSession
->getHostName(), cert_subject
, sal_True
);
490 xCertificateContainer
->addCertificate(
491 pSession
->getHostName(), cert_subject
, sal_False
);
499 xCertificateContainer
->addCertificate(
500 pSession
->getHostName(), cert_subject
, sal_False
);
507 extern "C" void NeonSession_PreSendRequest( ne_request
* req
,
509 ne_buffer
* headers
)
511 // userdata -> value returned by 'create'
513 NeonSession
* pSession
= static_cast< NeonSession
* >( userdata
);
516 // If there is a proxy server in between, it shall never use
517 // cached data. We always want 'up-to-date' data.
518 ne_buffer_concat( headers
, "Pragma: no-cache", EOL
, NULL
);
519 // alternative, but understoud by HTTP 1.1 servers only:
520 // ne_buffer_concat( headers, "Cache-Control: max-age=0", EOL, NULL );
522 const RequestDataMap
* pRequestData
523 = static_cast< const RequestDataMap
* >(
524 pSession
->getRequestData() );
526 RequestDataMap::const_iterator it
= pRequestData
->find( req
);
527 if ( it
!= pRequestData
->end() )
529 if ( !(*it
).second
.aContentType
.isEmpty() )
531 char * pData
= headers
->data
;
532 if ( strstr( pData
, "Content-Type:" ) == NULL
)
535 = OUStringToOString( (*it
).second
.aContentType
,
536 RTL_TEXTENCODING_UTF8
);
537 ne_buffer_concat( headers
, "Content-Type: ",
538 aType
.getStr(), EOL
, NULL
);
542 if ( !(*it
).second
.aReferer
.isEmpty() )
544 char * pData
= headers
->data
;
545 if ( strstr( pData
, "Referer:" ) == NULL
)
548 = OUStringToOString( (*it
).second
.aReferer
,
549 RTL_TEXTENCODING_UTF8
);
550 ne_buffer_concat( headers
, "Referer: ",
551 aReferer
.getStr(), EOL
, NULL
);
556 const DAVRequestHeaders
& rHeaders
557 = pSession
->getRequestEnvironment().m_aRequestHeaders
;
559 DAVRequestHeaders::const_iterator
it1( rHeaders
.begin() );
560 const DAVRequestHeaders::const_iterator
end1( rHeaders
.end() );
562 while ( it1
!= end1
)
565 = OUStringToOString( (*it1
).first
,
566 RTL_TEXTENCODING_UTF8
);
568 = OUStringToOString( (*it1
).second
,
569 RTL_TEXTENCODING_UTF8
);
570 ne_buffer_concat( headers
, aHeader
.getStr(), ": ",
571 aValue
.getStr(), EOL
, NULL
);
579 bool NeonSession::m_bGlobalsInited
= false;
580 //See https://bugzilla.redhat.com/show_bug.cgi?id=544619#c4
581 //neon is threadsafe, but uses gnutls which is only thread-safe
582 //if initialized to be thread-safe. cups, unfortunately, generally
583 //initializes it first, and as non-thread-safe, leaving the entire
585 osl::Mutex aGlobalNeonMutex
;
586 NeonLockStore
NeonSession::m_aNeonLockStore
;
588 NeonSession::NeonSession(
589 const rtl::Reference
< DAVSessionFactory
> & rSessionFactory
,
590 const OUString
& inUri
,
591 const uno::Sequence
< beans::NamedValue
>& rFlags
,
592 const ucbhelper::InternetProxyDecider
& rProxyDecider
)
593 throw ( DAVException
)
594 : DAVSession( rSessionFactory
),
597 m_pRequestData( new RequestDataMap
),
598 m_rProxyDecider( rProxyDecider
)
600 NeonUri
theUri( inUri
);
601 m_aScheme
= theUri
.GetScheme();
602 m_aHostName
= theUri
.GetHost();
603 m_nPort
= theUri
.GetPort();
606 NeonSession::~NeonSession( )
608 if ( m_pHttpSession
)
611 osl::Guard
< osl::Mutex
> theGlobalGuard( aGlobalNeonMutex
);
612 ne_session_destroy( m_pHttpSession
);
616 delete static_cast< RequestDataMap
* >( m_pRequestData
);
619 void NeonSession::Init( const DAVRequestEnvironment
& rEnv
)
620 throw ( DAVException
)
622 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
627 void NeonSession::Init()
628 throw ( DAVException
)
630 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
632 bool bCreateNewSession
= false;
634 if ( m_pHttpSession
== 0 )
636 // Ensure that Neon sockets are initialized
637 osl::Guard
< osl::Mutex
> theGlobalGuard( aGlobalNeonMutex
);
638 if ( !m_bGlobalsInited
)
640 if ( ne_sock_init() != 0 )
641 throw DAVException( DAVException::DAV_SESSION_CREATE
,
642 NeonUri::makeConnectionEndPointString(
643 m_aHostName
, m_nPort
) );
645 // #122205# - libxml2 needs to be initialized once if used by
646 // multithreaded programs like OOo.
648 #if OSL_DEBUG_LEVEL > 0
649 // for more debug flags see ne_utils.h; NE_DEBUGGING must be defined
650 // while compiling neon in order to actually activate neon debug
652 ne_debug_init( stderr
, NE_DBG_FLUSH
662 m_bGlobalsInited
= true;
665 const ucbhelper::InternetProxyServer
& rProxyCfg
= getProxySettings();
667 m_aProxyName
= rProxyCfg
.aName
;
668 m_nProxyPort
= rProxyCfg
.nPort
;
670 // Not yet initialized. Create new session.
671 bCreateNewSession
= true;
675 // #112271# Check whether proxy settings are still valid (They may
676 // change at any time). If not, create new Neon session.
678 const ucbhelper::InternetProxyServer
& rProxyCfg
= getProxySettings();
680 if ( ( rProxyCfg
.aName
!= m_aProxyName
)
681 || ( rProxyCfg
.nPort
!= m_nProxyPort
) )
683 m_aProxyName
= rProxyCfg
.aName
;
684 m_nProxyPort
= rProxyCfg
.nPort
;
686 // new session needed, destroy old first
688 osl::Guard
< osl::Mutex
> theGlobalGuard( aGlobalNeonMutex
);
689 ne_session_destroy( m_pHttpSession
);
692 bCreateNewSession
= true;
696 if ( bCreateNewSession
)
698 // @@@ For FTP over HTTP proxy inUserInfo is needed to be able to
699 // build the complete request URI (including user:pass), but
700 // currently (0.22.0) neon does not allow to pass the user info
704 osl::Guard
< osl::Mutex
> theGlobalGuard( aGlobalNeonMutex
);
705 m_pHttpSession
= ne_session_create(
706 OUStringToOString( m_aScheme
, RTL_TEXTENCODING_UTF8
).getStr(),
707 /* theUri.GetUserInfo(),
708 @@@ for FTP via HTTP proxy, but not supported by Neon */
709 OUStringToOString( m_aHostName
, RTL_TEXTENCODING_UTF8
).getStr(),
713 if ( m_pHttpSession
== 0 )
714 throw DAVException( DAVException::DAV_SESSION_CREATE
,
715 NeonUri::makeConnectionEndPointString(
716 m_aHostName
, m_nPort
) );
718 // Register the session with the lock store
719 m_aNeonLockStore
.registerSession( m_pHttpSession
);
721 if ( m_aScheme
.equalsIgnoreAsciiCase(
722 OUString( "https" ) ) )
724 // Set a failure callback for certificate check
726 m_pHttpSession
, NeonSession_CertificationNotify
, this);
728 // Tell Neon to tell the SSL library used (OpenSSL or
729 // GnuTLS, I guess) to use a default set of root
731 ne_ssl_trust_default_ca(m_pHttpSession
);
734 // Add hooks (i.e. for adding additional headers to the request)
737 /* Hook called when a request is created. */
738 //typedef void (*ne_create_request_fn)(ne_request *req, void *userdata,
739 // const char *method, const char *path);
741 ne_hook_create_request( m_pHttpSession
, create_req_hook_fn
, this );
744 /* Hook called before the request is sent. 'header' is the raw HTTP
745 * header before the trailing CRLF is added: add in more here. */
746 //typedef void (*ne_pre_send_fn)(ne_request *req, void *userdata,
747 // ne_buffer *header);
749 ne_hook_pre_send( m_pHttpSession
, NeonSession_PreSendRequest
, this );
751 /* Hook called after the request is sent. May return:
752 * NE_OK everything is okay
753 * NE_RETRY try sending the request again.
754 * anything else signifies an error, and the request is failed. The
755 * return code is passed back the _dispatch caller, so the session error
756 * must also be set appropriately (ne_set_error).
758 //typedef int (*ne_post_send_fn)(ne_request *req, void *userdata,
759 // const ne_status *status);
761 ne_hook_post_send( m_pHttpSession
, post_send_req_hook_fn
, this );
763 /* Hook called when the request is destroyed. */
764 //typedef void (*ne_destroy_req_fn)(ne_request *req, void *userdata);
766 ne_hook_destroy_request( m_pHttpSession
, destroy_req_hook_fn
, this );
768 /* Hook called when the session is destroyed. */
769 //typedef void (*ne_destroy_sess_fn)(void *userdata);
771 ne_hook_destroy_session( m_pHttpSession
, destroy_sess_hook_fn
, this );
774 if ( !m_aProxyName
.isEmpty() )
776 ne_session_proxy( m_pHttpSession
,
779 RTL_TEXTENCODING_UTF8
).getStr(),
784 if ( noKeepAlive(m_aFlags
) )
785 ne_set_session_flag( m_pHttpSession
, NE_SESSFLAG_PERSIST
, 0 );
787 // Register for redirects.
788 ne_redirect_register( m_pHttpSession
);
790 // authentication callbacks.
792 ne_add_server_auth( m_pHttpSession
, NE_AUTH_ALL
, NeonSession_NeonAuth
, this );
793 ne_add_proxy_auth ( m_pHttpSession
, NE_AUTH_ALL
, NeonSession_NeonAuth
, this );
795 ne_set_server_auth( m_pHttpSession
, NeonSession_NeonAuth
, this );
796 ne_set_proxy_auth ( m_pHttpSession
, NeonSession_NeonAuth
, this );
801 sal_Bool
NeonSession::CanUse( const OUString
& inUri
,
802 const uno::Sequence
< beans::NamedValue
>& rFlags
)
806 NeonUri
theUri( inUri
);
807 if ( ( theUri
.GetPort() == m_nPort
) &&
808 ( theUri
.GetHost() == m_aHostName
) &&
809 ( theUri
.GetScheme() == m_aScheme
) &&
810 ( rFlags
== m_aFlags
) )
813 catch ( DAVException
const & )
820 sal_Bool
NeonSession::UsesProxy()
823 return !m_aProxyName
.isEmpty() ;
826 void NeonSession::OPTIONS( const OUString
& inPath
,
827 DAVCapabilities
& outCapabilities
,
828 const DAVRequestEnvironment
& rEnv
)
829 throw( DAVException
)
831 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
835 HttpServerCapabilities servercaps
;
836 memset( &servercaps
, 0, sizeof( servercaps
) );
838 int theRetVal
= ne_options( m_pHttpSession
,
840 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
843 HandleError( theRetVal
, inPath
, rEnv
);
845 outCapabilities
.class1
= !!servercaps
.dav_class1
;
846 outCapabilities
.class2
= !!servercaps
.dav_class2
;
847 outCapabilities
.executable
= !!servercaps
.dav_executable
;
850 void NeonSession::PROPFIND( const OUString
& inPath
,
852 const std::vector
< OUString
> & inPropNames
,
853 std::vector
< DAVResource
> & ioResources
,
854 const DAVRequestEnvironment
& rEnv
)
855 throw ( DAVException
)
857 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
861 int theRetVal
= NE_OK
;
862 NeonPropFindRequest
theRequest( m_pHttpSession
,
864 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
870 HandleError( theRetVal
, inPath
, rEnv
);
873 void NeonSession::PROPFIND( const OUString
& inPath
,
875 std::vector
< DAVResourceInfo
> & ioResInfo
,
876 const DAVRequestEnvironment
& rEnv
)
877 throw( DAVException
)
879 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
883 int theRetVal
= NE_OK
;
884 NeonPropFindRequest
theRequest( m_pHttpSession
,
886 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
891 HandleError( theRetVal
, inPath
, rEnv
);
894 void NeonSession::PROPPATCH( const OUString
& inPath
,
895 const std::vector
< ProppatchValue
> & inValues
,
896 const DAVRequestEnvironment
& rEnv
)
897 throw( DAVException
)
899 /* @@@ Which standard live properties can be set by the client?
900 This is a known WebDAV RFC issue ( verified: 04/10/2001 )
901 --> http://www.ics.uci.edu/pub/ietf/webdav/protocol/issues.html
903 mod_dav implementation:
905 creationdate r ( File System prop )
907 getcontentlanguage r ( #ifdef DAV_DISABLE_WRITEABLE_PROPS )
908 getcontentlength r ( File System prop )
909 getcontenttype r ( #ifdef DAV_DISABLE_WRITEABLE_PROPS )
910 getetag r ( File System prop )
911 getlastmodified r ( File System prop )
916 executable w ( #ifndef WIN32 )
918 All dead properties are of course writable.
921 int theRetVal
= NE_OK
;
923 int n
; // for the "for" loop
925 // Generate the list of properties we want to set.
926 int nPropCount
= inValues
.size();
927 ne_proppatch_operation
* pItems
928 = new ne_proppatch_operation
[ nPropCount
+ 1 ];
929 for ( n
= 0; n
< nPropCount
; ++n
)
931 const ProppatchValue
& rValue
= inValues
[ n
];
933 // Split fullname into namespace and name!
934 ne_propname
* pName
= new ne_propname
;
935 DAVProperties::createNeonPropName( rValue
.name
, *pName
);
936 pItems
[ n
].name
= pName
;
938 if ( rValue
.operation
== PROPSET
)
940 pItems
[ n
].type
= ne_propset
;
942 OUString aStringValue
;
943 if ( DAVProperties::isUCBDeadProperty( *pName
) )
945 // DAV dead property added by WebDAV UCP?
946 if ( !UCBDeadPropertyValue::toXML( rValue
.value
,
950 pItems
[ n
].value
= 0;
951 theRetVal
= NE_ERROR
;
956 else if ( !( rValue
.value
>>= aStringValue
) )
958 // complex properties...
959 if ( rValue
.name
== DAVProperties::SOURCE
)
961 uno::Sequence
< ucb::Link
> aLinks
;
962 if ( rValue
.value
>>= aLinks
)
964 LinkSequence::toXML( aLinks
, aStringValue
);
969 pItems
[ n
].value
= 0;
970 theRetVal
= NE_ERROR
;
977 OSL_FAIL( "NeonSession::PROPPATCH - unsupported type!" );
979 pItems
[ n
].value
= 0;
980 theRetVal
= NE_ERROR
;
986 = strdup( OUStringToOString( aStringValue
,
987 RTL_TEXTENCODING_UTF8
).getStr() );
991 pItems
[ n
].type
= ne_propremove
;
992 pItems
[ n
].value
= 0;
996 if ( theRetVal
== NE_OK
)
998 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1002 pItems
[ n
].name
= 0;
1004 theRetVal
= ne_proppatch( m_pHttpSession
,
1006 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1010 for ( n
= 0; n
< nPropCount
; ++n
)
1012 free( (void *)pItems
[ n
].name
->name
);
1013 delete pItems
[ n
].name
;
1014 free( (void *)pItems
[ n
].value
);
1019 HandleError( theRetVal
, inPath
, rEnv
);
1022 void NeonSession::HEAD( const OUString
& inPath
,
1023 const std::vector
< OUString
> & inHeaderNames
,
1024 DAVResource
& ioResource
,
1025 const DAVRequestEnvironment
& rEnv
)
1026 throw( DAVException
)
1028 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1032 int theRetVal
= NE_OK
;
1033 NeonHeadRequest
theRequest( m_pHttpSession
,
1039 HandleError( theRetVal
, inPath
, rEnv
);
1042 uno::Reference
< io::XInputStream
>
1043 NeonSession::GET( const OUString
& inPath
,
1044 const DAVRequestEnvironment
& rEnv
)
1045 throw ( DAVException
)
1047 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1051 rtl::Reference
< NeonInputStream
> xInputStream( new NeonInputStream
);
1052 NeonRequestContext
aCtx( xInputStream
);
1053 int theRetVal
= GET( m_pHttpSession
,
1055 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1056 NeonSession_ResponseBlockReader
,
1060 HandleError( theRetVal
, inPath
, rEnv
);
1062 return uno::Reference
< io::XInputStream
>( xInputStream
.get() );
1065 void NeonSession::GET( const OUString
& inPath
,
1066 uno::Reference
< io::XOutputStream
> & ioOutputStream
,
1067 const DAVRequestEnvironment
& rEnv
)
1068 throw ( DAVException
)
1070 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1074 NeonRequestContext
aCtx( ioOutputStream
);
1075 int theRetVal
= GET( m_pHttpSession
,
1077 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1078 NeonSession_ResponseBlockWriter
,
1082 HandleError( theRetVal
, inPath
, rEnv
);
1085 uno::Reference
< io::XInputStream
>
1086 NeonSession::GET( const OUString
& inPath
,
1087 const std::vector
< OUString
> & inHeaderNames
,
1088 DAVResource
& ioResource
,
1089 const DAVRequestEnvironment
& rEnv
)
1090 throw ( DAVException
)
1092 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1096 ioResource
.uri
= inPath
;
1097 ioResource
.properties
.clear();
1099 rtl::Reference
< NeonInputStream
> xInputStream( new NeonInputStream
);
1100 NeonRequestContext
aCtx( xInputStream
, inHeaderNames
, ioResource
);
1101 int theRetVal
= GET( m_pHttpSession
,
1103 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1104 NeonSession_ResponseBlockReader
,
1108 HandleError( theRetVal
, inPath
, rEnv
);
1110 return uno::Reference
< io::XInputStream
>( xInputStream
.get() );
1113 void NeonSession::GET( const OUString
& inPath
,
1114 uno::Reference
< io::XOutputStream
> & ioOutputStream
,
1115 const std::vector
< OUString
> & inHeaderNames
,
1116 DAVResource
& ioResource
,
1117 const DAVRequestEnvironment
& rEnv
)
1118 throw ( DAVException
)
1120 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1124 ioResource
.uri
= inPath
;
1125 ioResource
.properties
.clear();
1127 NeonRequestContext
aCtx( ioOutputStream
, inHeaderNames
, ioResource
);
1128 int theRetVal
= GET( m_pHttpSession
,
1130 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1131 NeonSession_ResponseBlockWriter
,
1135 HandleError( theRetVal
, inPath
, rEnv
);
1138 void NeonSession::PUT( const OUString
& inPath
,
1139 const uno::Reference
< io::XInputStream
> & inInputStream
,
1140 const DAVRequestEnvironment
& rEnv
)
1141 throw ( DAVException
)
1143 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1145 uno::Sequence
< sal_Int8
> aDataToSend
;
1146 if ( !getDataFromInputStream( inInputStream
, aDataToSend
, false ) )
1147 throw DAVException( DAVException::DAV_INVALID_ARG
);
1151 int theRetVal
= PUT( m_pHttpSession
,
1153 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1154 reinterpret_cast< const char * >(
1155 aDataToSend
.getConstArray() ),
1156 aDataToSend
.getLength() );
1158 HandleError( theRetVal
, inPath
, rEnv
);
1161 uno::Reference
< io::XInputStream
>
1162 NeonSession::POST( const OUString
& inPath
,
1163 const OUString
& rContentType
,
1164 const OUString
& rReferer
,
1165 const uno::Reference
< io::XInputStream
> & inInputStream
,
1166 const DAVRequestEnvironment
& rEnv
)
1167 throw ( DAVException
)
1169 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1171 uno::Sequence
< sal_Int8
> aDataToSend
;
1172 if ( !getDataFromInputStream( inInputStream
, aDataToSend
, true ) )
1173 throw DAVException( DAVException::DAV_INVALID_ARG
);
1177 rtl::Reference
< NeonInputStream
> xInputStream( new NeonInputStream
);
1178 NeonRequestContext
aCtx( xInputStream
);
1179 int theRetVal
= POST( m_pHttpSession
,
1181 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1182 reinterpret_cast< const char * >(
1183 aDataToSend
.getConstArray() ),
1184 NeonSession_ResponseBlockReader
,
1189 HandleError( theRetVal
, inPath
, rEnv
);
1191 return uno::Reference
< io::XInputStream
>( xInputStream
.get() );
1194 void NeonSession::POST( const OUString
& inPath
,
1195 const OUString
& rContentType
,
1196 const OUString
& rReferer
,
1197 const uno::Reference
< io::XInputStream
> & inInputStream
,
1198 uno::Reference
< io::XOutputStream
> & oOutputStream
,
1199 const DAVRequestEnvironment
& rEnv
)
1200 throw ( DAVException
)
1202 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1204 uno::Sequence
< sal_Int8
> aDataToSend
;
1205 if ( !getDataFromInputStream( inInputStream
, aDataToSend
, true ) )
1206 throw DAVException( DAVException::DAV_INVALID_ARG
);
1210 NeonRequestContext
aCtx( oOutputStream
);
1211 int theRetVal
= POST( m_pHttpSession
,
1213 inPath
, RTL_TEXTENCODING_UTF8
).getStr(),
1214 reinterpret_cast< const char * >(
1215 aDataToSend
.getConstArray() ),
1216 NeonSession_ResponseBlockWriter
,
1221 HandleError( theRetVal
, inPath
, rEnv
);
1224 void NeonSession::MKCOL( const OUString
& inPath
,
1225 const DAVRequestEnvironment
& rEnv
)
1226 throw ( DAVException
)
1228 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1232 int theRetVal
= ne_mkcol( m_pHttpSession
,
1234 inPath
, RTL_TEXTENCODING_UTF8
).getStr() );
1236 HandleError( theRetVal
, inPath
, rEnv
);
1239 void NeonSession::COPY( const OUString
& inSourceURL
,
1240 const OUString
& inDestinationURL
,
1241 const DAVRequestEnvironment
& rEnv
,
1242 sal_Bool inOverWrite
)
1243 throw ( DAVException
)
1245 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1249 NeonUri
theSourceUri( inSourceURL
);
1250 NeonUri
theDestinationUri( inDestinationURL
);
1252 int theRetVal
= ne_copy( m_pHttpSession
,
1253 inOverWrite
? 1 : 0,
1256 theSourceUri
.GetPath(),
1257 RTL_TEXTENCODING_UTF8
).getStr(),
1259 theDestinationUri
.GetPath(),
1260 RTL_TEXTENCODING_UTF8
).getStr() );
1262 HandleError( theRetVal
, inSourceURL
, rEnv
);
1265 void NeonSession::MOVE( const OUString
& inSourceURL
,
1266 const OUString
& inDestinationURL
,
1267 const DAVRequestEnvironment
& rEnv
,
1268 sal_Bool inOverWrite
)
1269 throw ( DAVException
)
1271 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1275 NeonUri
theSourceUri( inSourceURL
);
1276 NeonUri
theDestinationUri( inDestinationURL
);
1277 int theRetVal
= ne_move( m_pHttpSession
,
1278 inOverWrite
? 1 : 0,
1280 theSourceUri
.GetPath(),
1281 RTL_TEXTENCODING_UTF8
).getStr(),
1283 theDestinationUri
.GetPath(),
1284 RTL_TEXTENCODING_UTF8
).getStr() );
1286 HandleError( theRetVal
, inSourceURL
, rEnv
);
1289 void NeonSession::DESTROY( const OUString
& inPath
,
1290 const DAVRequestEnvironment
& rEnv
)
1291 throw ( DAVException
)
1293 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1297 int theRetVal
= ne_delete( m_pHttpSession
,
1299 inPath
, RTL_TEXTENCODING_UTF8
).getStr() );
1301 HandleError( theRetVal
, inPath
, rEnv
);
1306 sal_Int32
lastChanceToSendRefreshRequest( TimeValue
const & rStart
,
1310 osl_getSystemTime( &aEnd
);
1312 // Try to estimate a safe absolute time for sending the
1313 // lock refresh request.
1314 sal_Int32 lastChanceToSendRefreshRequest
= -1;
1315 if ( timeout
!= NE_TIMEOUT_INFINITE
)
1317 sal_Int32 calltime
= aEnd
.Seconds
- rStart
.Seconds
;
1318 if ( calltime
<= timeout
)
1320 lastChanceToSendRefreshRequest
1321 = aEnd
.Seconds
+ timeout
- calltime
;
1325 OSL_TRACE( "No chance to refresh lock before timeout!" );
1328 return lastChanceToSendRefreshRequest
;
1334 void NeonSession::LOCK( const OUString
& inPath
,
1336 const DAVRequestEnvironment
& rEnv
)
1337 throw ( DAVException
)
1339 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1343 /* Create a depth zero, exclusive write lock, with default timeout
1344 * (allowing a server to pick a default). token, owner and uri are
1346 NeonLock
* theLock
= ne_lock_create();
1350 ne_uri_parse( OUStringToOString( makeAbsoluteURL( inPath
),
1351 RTL_TEXTENCODING_UTF8
).getStr(),
1353 theLock
->uri
= aUri
;
1355 // Set the lock depth
1356 switch( rLock
.Depth
)
1358 case ucb::LockDepth_ZERO
:
1359 theLock
->depth
= NE_DEPTH_ZERO
;
1361 case ucb::LockDepth_ONE
:
1362 theLock
->depth
= NE_DEPTH_ONE
;
1364 case ucb::LockDepth_INFINITY
:
1365 theLock
->depth
= NE_DEPTH_INFINITE
;
1368 throw DAVException( DAVException::DAV_INVALID_ARG
);
1371 // Set the lock scope
1372 switch ( rLock
.Scope
)
1374 case ucb::LockScope_EXCLUSIVE
:
1375 theLock
->scope
= ne_lockscope_exclusive
;
1377 case ucb::LockScope_SHARED
:
1378 theLock
->scope
= ne_lockscope_shared
;
1381 throw DAVException( DAVException::DAV_INVALID_ARG
);
1384 // Set the lock timeout
1385 theLock
->timeout
= (long)rLock
.Timeout
;
1387 // Set the lock owner
1389 rLock
.Owner
>>= aValue
;
1391 ne_strdup( OUStringToOString( aValue
,
1392 RTL_TEXTENCODING_UTF8
).getStr() );
1393 TimeValue startCall
;
1394 osl_getSystemTime( &startCall
);
1396 int theRetVal
= ne_lock( m_pHttpSession
, theLock
);
1398 if ( theRetVal
== NE_OK
)
1400 m_aNeonLockStore
.addLock( theLock
,
1402 lastChanceToSendRefreshRequest(
1403 startCall
, theLock
->timeout
) );
1405 uno::Sequence
< OUString
> aTokens( 1 );
1406 aTokens
[ 0 ] = OUString::createFromAscii( theLock
->token
);
1407 rLock
.LockTokens
= aTokens
;
1409 OSL_TRACE( "NeonSession::LOCK: created lock for %s. token: %s",
1410 OUStringToOString( makeAbsoluteURL( inPath
),
1411 RTL_TEXTENCODING_UTF8
).getStr(),
1416 ne_lock_destroy( theLock
);
1418 OSL_TRACE( "NeonSession::LOCK: obtaining lock for %s failed!",
1419 OUStringToOString( makeAbsoluteURL( inPath
),
1420 RTL_TEXTENCODING_UTF8
).getStr() );
1423 HandleError( theRetVal
, inPath
, rEnv
);
1426 // Refresh existing lock
1427 sal_Int64
NeonSession::LOCK( const OUString
& inPath
,
1429 const DAVRequestEnvironment
& rEnv
)
1430 throw ( DAVException
)
1432 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1434 // Try to get the neon lock from lock store
1436 = m_aNeonLockStore
.findByUri( makeAbsoluteURL( inPath
) );
1438 throw DAVException( DAVException::DAV_NOT_LOCKED
);
1442 // refresh existing lock.
1443 theLock
->timeout
= static_cast< long >( nTimeout
);
1445 TimeValue startCall
;
1446 osl_getSystemTime( &startCall
);
1448 int theRetVal
= ne_lock_refresh( m_pHttpSession
, theLock
);
1450 if ( theRetVal
== NE_OK
)
1452 m_aNeonLockStore
.updateLock( theLock
,
1453 lastChanceToSendRefreshRequest(
1454 startCall
, theLock
->timeout
) );
1457 HandleError( theRetVal
, inPath
, rEnv
);
1459 return theLock
->timeout
;
1462 // Refresh existing lock
1463 bool NeonSession::LOCK( NeonLock
* pLock
,
1464 sal_Int32
& rlastChanceToSendRefreshRequest
)
1466 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1468 #if OSL_DEBUG_LEVEL > 0
1469 char * p
= ne_uri_unparse( &(pLock
->uri
) );
1470 OSL_TRACE( "NeonSession::LOCK: Refreshing lock for %s.", p
);
1474 // refresh existing lock.
1476 TimeValue startCall
;
1477 osl_getSystemTime( &startCall
);
1479 if ( ne_lock_refresh( m_pHttpSession
, pLock
) == NE_OK
)
1481 rlastChanceToSendRefreshRequest
1482 = lastChanceToSendRefreshRequest( startCall
, pLock
->timeout
);
1484 OSL_TRACE( "Lock successfully refreshed." );
1489 OSL_TRACE( "Lock not refreshed!" );
1494 void NeonSession::UNLOCK( const OUString
& inPath
,
1495 const DAVRequestEnvironment
& rEnv
)
1496 throw ( DAVException
)
1498 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1500 // get the neon lock from lock store
1502 = m_aNeonLockStore
.findByUri( makeAbsoluteURL( inPath
) );
1504 throw DAVException( DAVException::DAV_NOT_LOCKED
);
1508 int theRetVal
= ne_unlock( m_pHttpSession
, theLock
);
1510 if ( theRetVal
== NE_OK
)
1512 m_aNeonLockStore
.removeLock( theLock
);
1513 ne_lock_destroy( theLock
);
1517 OSL_TRACE( "NeonSession::UNLOCK: unlocking of %s failed.",
1518 OUStringToOString( makeAbsoluteURL( inPath
),
1519 RTL_TEXTENCODING_UTF8
).getStr() );
1522 HandleError( theRetVal
, inPath
, rEnv
);
1525 bool NeonSession::UNLOCK( NeonLock
* pLock
)
1527 osl::Guard
< osl::Mutex
> theGuard( m_aMutex
);
1529 #if OSL_DEBUG_LEVEL > 0
1530 char * p
= ne_uri_unparse( &(pLock
->uri
) );
1531 OSL_TRACE( "NeonSession::UNLOCK: Unlocking %s.", p
);
1535 if ( ne_unlock( m_pHttpSession
, pLock
) == NE_OK
)
1537 OSL_TRACE( "UNLOCK succeeded." );
1542 OSL_TRACE( "UNLOCK failed!" );
1547 void NeonSession::abort()
1548 throw ( DAVException
)
1550 SAL_INFO("ucb.ucp.webdav", "neon commands cannot be aborted");
1553 const ucbhelper::InternetProxyServer
& NeonSession::getProxySettings() const
1555 if ( m_aScheme
== "http" || m_aScheme
== "https" )
1557 return m_rProxyDecider
.getProxy( m_aScheme
,
1563 return m_rProxyDecider
.getProxy( m_aScheme
,
1564 OUString() /* not used */,
1565 -1 /* not used */ );
1571 bool containsLocktoken( const uno::Sequence
< ucb::Lock
> & rLocks
,
1572 const char * token
)
1574 for ( sal_Int32 n
= 0; n
< rLocks
.getLength(); ++n
)
1576 const uno::Sequence
< OUString
> & rTokens
1577 = rLocks
[ n
].LockTokens
;
1578 for ( sal_Int32 m
= 0; m
< rTokens
.getLength(); ++m
)
1580 if ( rTokens
[ m
].equalsAscii( token
) )
1589 bool NeonSession::removeExpiredLocktoken( const OUString
& inURL
,
1590 const DAVRequestEnvironment
& rEnv
)
1592 NeonLock
* theLock
= m_aNeonLockStore
.findByUri( inURL
);
1596 // do a lockdiscovery to check whether this lock is still valid.
1599 // @@@ Alternative: use ne_lock_discover() => less overhead
1601 std::vector
< DAVResource
> aResources
;
1602 std::vector
< OUString
> aPropNames
;
1603 aPropNames
.push_back( DAVProperties::LOCKDISCOVERY
);
1605 PROPFIND( rEnv
.m_aRequestURI
, DAVZERO
, aPropNames
, aResources
, rEnv
);
1607 if ( aResources
.empty() )
1610 std::vector
< DAVPropertyValue
>::const_iterator it
1611 = aResources
[ 0 ].properties
.begin();
1612 std::vector
< DAVPropertyValue
>::const_iterator end
1613 = aResources
[ 0 ].properties
.end();
1617 if ( (*it
).Name
.equals( DAVProperties::LOCKDISCOVERY
) )
1619 uno::Sequence
< ucb::Lock
> aLocks
;
1620 if ( !( (*it
).Value
>>= aLocks
) )
1623 if ( !containsLocktoken( aLocks
, theLock
->token
) )
1635 // No lockdiscovery prop in propfind result / locktoken not found
1636 // in propfind result -> not locked
1637 OSL_TRACE( "NeonSession::removeExpiredLocktoken: Removing "
1638 " expired lock token for %s. token: %s",
1639 OUStringToOString( inURL
,
1640 RTL_TEXTENCODING_UTF8
).getStr(),
1643 m_aNeonLockStore
.removeLock( theLock
);
1644 ne_lock_destroy( theLock
);
1647 catch ( DAVException
const & )
1653 // Common error handler
1654 void NeonSession::HandleError( int nError
,
1655 const OUString
& inPath
,
1656 const DAVRequestEnvironment
& rEnv
)
1657 throw ( DAVException
)
1659 m_aEnv
= DAVRequestEnvironment();
1661 // Map error code to DAVException.
1667 case NE_ERROR
: // Generic error
1669 OUString aText
= OUString::createFromAscii(
1670 ne_get_error( m_pHttpSession
) );
1672 sal_uInt16 code
= makeStatusCode( aText
);
1674 if ( code
== SC_LOCKED
)
1676 if ( m_aNeonLockStore
.findByUri(
1677 makeAbsoluteURL( inPath
) ) == 0 )
1679 // locked by 3rd party
1680 throw DAVException( DAVException::DAV_LOCKED
);
1684 // locked by ourself
1685 throw DAVException( DAVException::DAV_LOCKED_SELF
);
1689 // Special handling for 400 and 412 status codes, which may indicate
1690 // that a lock previously obtained by us has been released meanwhile
1691 // by the server. Unfortunately, RFC is not clear at this point,
1692 // thus server implementations behave different...
1693 else if ( code
== SC_BAD_REQUEST
|| code
== SC_PRECONDITION_FAILED
)
1695 if ( removeExpiredLocktoken( makeAbsoluteURL( inPath
), rEnv
) )
1696 throw DAVException( DAVException::DAV_LOCK_EXPIRED
);
1699 throw DAVException( DAVException::DAV_HTTP_ERROR
, aText
, code
);
1701 case NE_LOOKUP
: // Name lookup failed.
1702 throw DAVException( DAVException::DAV_HTTP_LOOKUP
,
1703 NeonUri::makeConnectionEndPointString(
1704 m_aHostName
, m_nPort
) );
1706 case NE_AUTH
: // User authentication failed on server
1707 throw DAVException( DAVException::DAV_HTTP_AUTH
,
1708 NeonUri::makeConnectionEndPointString(
1709 m_aHostName
, m_nPort
) );
1711 case NE_PROXYAUTH
: // User authentication failed on proxy
1712 throw DAVException( DAVException::DAV_HTTP_AUTHPROXY
,
1713 NeonUri::makeConnectionEndPointString(
1714 m_aProxyName
, m_nProxyPort
) );
1716 case NE_CONNECT
: // Could not connect to server
1717 throw DAVException( DAVException::DAV_HTTP_CONNECT
,
1718 NeonUri::makeConnectionEndPointString(
1719 m_aHostName
, m_nPort
) );
1721 case NE_TIMEOUT
: // Connection timed out
1722 throw DAVException( DAVException::DAV_HTTP_TIMEOUT
,
1723 NeonUri::makeConnectionEndPointString(
1724 m_aHostName
, m_nPort
) );
1726 case NE_FAILED
: // The precondition failed
1727 throw DAVException( DAVException::DAV_HTTP_FAILED
,
1728 NeonUri::makeConnectionEndPointString(
1729 m_aHostName
, m_nPort
) );
1731 case NE_RETRY
: // Retry request (ne_end_request ONLY)
1732 throw DAVException( DAVException::DAV_HTTP_RETRY
,
1733 NeonUri::makeConnectionEndPointString(
1734 m_aHostName
, m_nPort
) );
1738 NeonUri
aUri( ne_redirect_location( m_pHttpSession
) );
1740 DAVException::DAV_HTTP_REDIRECT
, aUri
.GetURI() );
1744 OSL_TRACE( "NeonSession::HandleError : Unknown Neon error code!" );
1745 throw DAVException( DAVException::DAV_HTTP_ERROR
,
1746 OUString::createFromAscii(
1747 ne_get_error( m_pHttpSession
) ) );
1754 void runResponseHeaderHandler( void * userdata
,
1755 const char * value
)
1757 OUString
aHeader( OUString::createFromAscii( value
) );
1758 sal_Int32 nPos
= aHeader
.indexOf( ':' );
1762 OUString
aHeaderName( aHeader
.copy( 0, nPos
) );
1764 NeonRequestContext
* pCtx
1765 = static_cast< NeonRequestContext
* >( userdata
);
1767 // Note: Empty vector means that all headers are requested.
1768 bool bIncludeIt
= ( pCtx
->pHeaderNames
->empty() );
1772 // Check whether this header was requested.
1773 std::vector
< OUString
>::const_iterator
it(
1774 pCtx
->pHeaderNames
->begin() );
1775 const std::vector
< OUString
>::const_iterator
end(
1776 pCtx
->pHeaderNames
->end() );
1780 // header names are case insensitive
1781 if ( (*it
).equalsIgnoreAsciiCase( aHeaderName
) )
1783 aHeaderName
= (*it
);
1795 // Create & set the PropertyValue
1796 DAVPropertyValue thePropertyValue
;
1797 thePropertyValue
.IsCaseSensitive
= false;
1798 thePropertyValue
.Name
= aHeaderName
;
1800 if ( nPos
< aHeader
.getLength() )
1801 thePropertyValue
.Value
<<= aHeader
.copy( nPos
+ 1 ).trim();
1803 // Add the newly created PropertyValue
1804 pCtx
->pResource
->properties
.push_back( thePropertyValue
);
1811 int NeonSession::GET( ne_session
* sess
,
1813 ne_block_reader reader
,
1817 //struct get_context ctx;
1818 ne_request
* req
= ne_request_create( sess
, "GET", uri
);
1822 = ne_decompress_reader( req
, ne_accept_2xx
, reader
, userdata
);
1825 osl::Guard
< osl::Mutex
> theGlobalGuard( aGlobalNeonMutex
);
1826 ret
= ne_request_dispatch( req
);
1831 void *cursor
= NULL
;
1832 const char *name
, *value
;
1833 while ( ( cursor
= ne_response_header_iterate(
1834 req
, cursor
, &name
, &value
) ) != NULL
)
1838 ne_snprintf(buffer
, sizeof buffer
, "%s: %s", name
, value
);
1839 runResponseHeaderHandler(userdata
, buffer
);
1843 if ( ret
== NE_OK
&& ne_get_status( req
)->klass
!= 2 )
1847 ne_decompress_destroy(dc
);
1849 ne_request_destroy( req
);
1853 int NeonSession::PUT( ne_session
* sess
,
1855 const char * buffer
,
1858 ne_request
* req
= ne_request_create( sess
, "PUT", uri
);
1861 ne_lock_using_resource( req
, uri
, 0 );
1862 ne_lock_using_parent( req
, uri
);
1864 ne_set_request_body_buffer( req
, buffer
, size
);
1867 osl::Guard
< osl::Mutex
> theGlobalGuard( aGlobalNeonMutex
);
1868 ret
= ne_request_dispatch( req
);
1871 if ( ret
== NE_OK
&& ne_get_status( req
)->klass
!= 2 )
1874 ne_request_destroy( req
);
1878 int NeonSession::POST( ne_session
* sess
,
1880 const char * buffer
,
1881 ne_block_reader reader
,
1883 const OUString
& rContentType
,
1884 const OUString
& rReferer
)
1886 ne_request
* req
= ne_request_create( sess
, "POST", uri
);
1887 //struct get_context ctx;
1890 RequestDataMap
* pData
= 0;
1892 if ( !rContentType
.isEmpty() || !rReferer
.isEmpty() )
1894 // Remember contenttype and referer. Data will be added to HTTP request
1895 // header in in 'PreSendRequest' callback.
1896 pData
= static_cast< RequestDataMap
* >( m_pRequestData
);
1897 (*pData
)[ req
] = RequestData( rContentType
, rReferer
);
1903 //ctx.session = sess;
1905 ///* Read the value of the Content-Length header into ctx.total */
1906 //ne_add_response_header_handler( req, "Content-Length",
1907 // ne_handle_numeric_header, &ctx.total );
1909 ne_add_response_body_reader( req
, ne_accept_2xx
, reader
, userdata
);
1911 ne_set_request_body_buffer( req
, buffer
, strlen( buffer
) );
1914 osl::Guard
< osl::Mutex
> theGlobalGuard( aGlobalNeonMutex
);
1915 ret
= ne_request_dispatch( req
);
1921 if ( ret
== NE_OK
&& ne_get_status( req
)->klass
!= 2 )
1924 ne_request_destroy( req
);
1928 // Remove request data from session's list.
1929 RequestDataMap::iterator it
= pData
->find( req
);
1930 if ( it
!= pData
->end() )
1938 NeonSession::getDataFromInputStream(
1939 const uno::Reference
< io::XInputStream
> & xStream
,
1940 uno::Sequence
< sal_Int8
> & rData
,
1941 bool bAppendTrailingZeroByte
)
1945 uno::Reference
< io::XSeekable
> xSeekable( xStream
, uno::UNO_QUERY
);
1946 if ( xSeekable
.is() )
1951 = sal::static_int_cast
<sal_Int32
>(xSeekable
->getLength());
1953 = xStream
->readBytes( rData
, nSize
);
1955 if ( nRead
== nSize
)
1957 if ( bAppendTrailingZeroByte
)
1959 rData
.realloc( nSize
+ 1 );
1960 rData
[ nSize
] = sal_Int8( 0 );
1965 catch ( io::NotConnectedException
const & )
1969 catch ( io::BufferSizeExceededException
const & )
1973 catch ( io::IOException
const & )
1975 // getLength, readBytes
1982 uno::Sequence
< sal_Int8
> aBuffer
;
1985 sal_Int32 nRead
= xStream
->readSomeBytes( aBuffer
, 65536 );
1988 if ( rData
.getLength() < ( nPos
+ nRead
) )
1989 rData
.realloc( nPos
+ nRead
);
1991 aBuffer
.realloc( nRead
);
1992 memcpy( (void*)( rData
.getArray() + nPos
),
1993 (const void*)aBuffer
.getConstArray(),
1997 aBuffer
.realloc( 0 );
1998 nRead
= xStream
->readSomeBytes( aBuffer
, 65536 );
2001 if ( bAppendTrailingZeroByte
)
2003 rData
.realloc( nPos
+ 1 );
2004 rData
[ nPos
] = sal_Int8( 0 );
2008 catch ( io::NotConnectedException
const & )
2012 catch ( io::BufferSizeExceededException
const & )
2016 catch ( io::IOException
const & )
2026 NeonSession::isDomainMatch( OUString certHostName
)
2028 OUString hostName
= getHostName();
2030 if (hostName
.equalsIgnoreAsciiCase( certHostName
) )
2033 if ( certHostName
.startsWith( "*" ) &&
2034 hostName
.getLength() >= certHostName
.getLength() )
2036 OUString cmpStr
= certHostName
.copy( 1 );
2038 if ( hostName
.matchIgnoreAsciiCase(
2039 cmpStr
, hostName
.getLength() - cmpStr
.getLength() ) )
2045 OUString
NeonSession::makeAbsoluteURL( OUString
const & rURL
) const
2049 // Is URL relative or already absolute?
2050 if ( rURL
[ 0 ] != '/' )
2053 return OUString( rURL
);
2058 memset( &aUri
, 0, sizeof( aUri
) );
2060 ne_fill_server_uri( m_pHttpSession
, &aUri
);
2062 = ne_strdup( OUStringToOString(
2063 rURL
, RTL_TEXTENCODING_UTF8
).getStr() );
2064 NeonUri
aNeonUri( &aUri
);
2065 ne_uri_free( &aUri
);
2066 return aNeonUri
.GetURI();
2069 catch ( DAVException
const & )
2076 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */