Update ooo320-m1
[ooovba.git] / ucb / source / ucp / webdav / NeonSession.cxx
blobcd9449e50d1e79cf4f713b73186758bf0e18fb17
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: NeonSession.cxx,v $
10 * $Revision: 1.55.12.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_ucb.hxx"
34 #include <hash_map>
35 #include <vector>
36 #include <string.h>
37 #include <rtl/string.h>
38 #include <ne_socket.h>
39 #include <ne_auth.h>
40 #include <ne_redirect.h>
41 #include <ne_locks.h>
42 #include <ne_ssl.h>
43 #include "libxml/parser.h"
44 #include "rtl/ustrbuf.hxx"
45 #include "comphelper/sequence.hxx"
46 #include "ucbhelper/simplecertificatevalidationrequest.hxx"
48 #include "DAVAuthListener.hxx"
49 #include "NeonTypes.hxx"
50 #include "NeonSession.hxx"
51 #include "NeonInputStream.hxx"
52 #include "NeonPropFindRequest.hxx"
53 #include "NeonHeadRequest.hxx"
54 #include "NeonUri.hxx"
55 #include "LinkSequence.hxx"
56 #include "UCBDeadPropertyValue.hxx"
58 #include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
59 #include <com/sun/star/security/XCertificate.hpp>
60 #include <com/sun/star/security/CertificateValidity.hpp>
61 #include <com/sun/star/security/CertificateContainerStatus.hpp>
62 #include <com/sun/star/security/CertificateContainer.hpp>
63 #include <com/sun/star/security/XCertificateContainer.hpp>
64 #include <com/sun/star/task/XMasterPasswordHandling.hpp>
65 #include <com/sun/star/xml/crypto/XSEInitializer.hpp>
67 using namespace com::sun::star;
68 using namespace webdav_ucp;
70 #define SEINITIALIZER_COMPONENT "com.sun.star.xml.crypto.SEInitializer"
72 #ifndef EOL
73 # define EOL "\r\n"
74 #endif
75 #include <ucbhelper/cancelcommandexecution.hxx>
77 // -------------------------------------------------------------------
78 // RequestData
79 // -------------------------------------------------------------------
81 struct RequestData
83 // POST
84 rtl::OUString aContentType;
85 rtl::OUString aReferer;
87 RequestData() {}
88 RequestData( const rtl::OUString & rContentType,
89 const rtl::OUString & rReferer )
90 : aContentType( rContentType ), aReferer( rReferer ) {}
93 // -------------------------------------------------------------------
94 // RequestDataMap
95 // -------------------------------------------------------------------
97 struct equalPtr
99 bool operator()( const ne_request* p1, const ne_request* p2 ) const
101 return p1 == p2;
105 struct hashPtr
107 size_t operator()( const ne_request* p ) const
109 return (size_t)p;
113 typedef std::hash_map
115 ne_request*,
116 RequestData,
117 hashPtr,
118 equalPtr
120 RequestDataMap;
122 // -------------------------------------------------------------------
123 // static members!
124 bool NeonSession::m_bGlobalsInited = false;
125 osl::Mutex NeonSession::m_aGlobalMutex;
126 // -------------------------------------------------------------------
127 // Helper fuction
128 // -------------------------------------------------------------------
129 static sal_uInt16 makeStatusCode( const rtl::OUString & rStatusText )
131 // Extract status code from session error string. Unfortunately
132 // neon provides no direct access to the status code...
134 if ( rStatusText.getLength() < 3 )
136 OSL_ENSURE(
137 sal_False, "makeStatusCode - status text string to short!" );
138 return 0;
141 sal_Int32 nPos = rStatusText.indexOf( ' ' );
142 if ( nPos == -1 )
144 OSL_ENSURE( sal_False, "makeStatusCode - wrong status text format!" );
145 return 0;
148 return sal_uInt16( rStatusText.copy( 0, nPos ).toInt32() );
151 static sal_uInt16 getStatusCode( HttpSession *pSession )
153 rtl::OUString aText = rtl::OUString::createFromAscii( ne_get_error( pSession ) );
154 return makeStatusCode( aText );
157 // -------------------------------------------------------------------
158 struct NeonRequestContext
160 uno::Reference< io::XOutputStream > xOutputStream;
161 rtl::Reference< NeonInputStream > xInputStream;
162 const std::vector< ::rtl::OUString > * pHeaderNames;
163 DAVResource * pResource;
165 NeonRequestContext( uno::Reference< io::XOutputStream > & xOutStrm )
166 : xOutputStream( xOutStrm ), xInputStream( 0 ),
167 pHeaderNames( 0 ), pResource( 0 ) {}
169 NeonRequestContext( const rtl::Reference< NeonInputStream > & xInStrm )
170 : xOutputStream( 0 ), xInputStream( xInStrm ),
171 pHeaderNames( 0 ), pResource( 0 ) {}
173 NeonRequestContext( uno::Reference< io::XOutputStream > & xOutStrm,
174 const std::vector< ::rtl::OUString > & inHeaderNames,
175 DAVResource & ioResource )
176 : xOutputStream( xOutStrm ), xInputStream( 0 ),
177 pHeaderNames( &inHeaderNames ), pResource( &ioResource ) {}
179 NeonRequestContext( const rtl::Reference< NeonInputStream > & xInStrm,
180 const std::vector< ::rtl::OUString > & inHeaderNames,
181 DAVResource & ioResource )
182 : xOutputStream( 0 ), xInputStream( xInStrm ),
183 pHeaderNames( &inHeaderNames ), pResource( &ioResource ) {}
186 //--------------------------------------------------------------------
187 //--------------------------------------------------------------------
189 // Callback functions
191 //--------------------------------------------------------------------
192 //--------------------------------------------------------------------
194 // -------------------------------------------------------------------
195 // ResponseBlockReader
196 // A simple Neon response_block_reader for use with an XInputStream
197 // -------------------------------------------------------------------
199 #if NEON_VERSION >= 0x0250
200 extern "C" int
201 #else
202 extern "C" void
203 #endif
204 NeonSession_ResponseBlockReader( void * inUserData,
205 const char * inBuf,
206 size_t inLen )
208 // neon calls this function with (inLen == 0)...
209 if ( inLen > 0 )
211 NeonRequestContext * pCtx
212 = static_cast< NeonRequestContext * >( inUserData );
214 rtl::Reference< NeonInputStream > xInputStream(
215 pCtx->xInputStream);
217 if ( xInputStream.is() )
218 xInputStream->AddToStream( inBuf, inLen );
220 #if NEON_VERSION >= 0x0250
221 return 0;
222 #endif
225 // -------------------------------------------------------------------
226 // ResponseBlockWriter
227 // A simple Neon response_block_reader for use with an XOutputStream
228 // -------------------------------------------------------------------
230 #if NEON_VERSION >= 0x0250
231 extern "C" int
232 #else
233 extern "C" void
234 #endif
235 NeonSession_ResponseBlockWriter( void * inUserData,
236 const char * inBuf,
237 size_t inLen )
239 // neon calls this function with (inLen == 0)...
240 if ( inLen > 0 )
242 NeonRequestContext * pCtx
243 = static_cast< NeonRequestContext * >( inUserData );
244 uno::Reference< io::XOutputStream > xOutputStream
245 = pCtx->xOutputStream;
247 if ( xOutputStream.is() )
249 const uno::Sequence< sal_Int8 > aSeq( (sal_Int8 *)inBuf, inLen );
250 xOutputStream->writeBytes( aSeq );
253 #if NEON_VERSION >= 0x0250
254 return 0;
255 #endif
258 // -------------------------------------------------------------------
259 extern "C" int NeonSession_NeonAuth( void * inUserData,
260 #ifdef NE_FEATURE_SSPI
261 const char * inAuthProtocol,
262 #endif
263 const char * inRealm,
264 int attempt,
265 char * inoutUserName,
266 char * inoutPassWord )
268 /* The callback used to request the username and password in the given
269 * realm. The username and password must be copied into the buffers
270 * which are both of size NE_ABUFSIZ. The 'attempt' parameter is zero
271 * on the first call to the callback, and increases by one each time
272 * an attempt to authenticate fails.
274 * The callback must return zero to indicate that authentication
275 * should be attempted with the username/password, or non-zero to
276 * cancel the request. (if non-zero, username and password are
277 * ignored.) */
279 #if 0
280 // Give'em only a limited mumber of retries..
281 if ( attempt > 9 )
283 // abort
284 return -1;
286 #endif
288 NeonSession * theSession = static_cast< NeonSession * >( inUserData );
289 DAVAuthListener * pListener
290 = theSession->getRequestEnvironment().m_xAuthListener.get();
291 if ( !pListener )
293 // abort
294 return -1;
296 rtl::OUString theUserName;
297 rtl::OUString thePassWord;
299 if ( attempt == 0 )
301 // neon does not handle username supplied with request URI (for
302 // instance when doing FTP over proxy - last checked: 0.23.5 )
306 rtl::OUString aUserInfo( theSession->getUserInfo() );
307 if ( aUserInfo.getLength() )
309 sal_Int32 nPos = aUserInfo.indexOf( ':' );
310 if ( nPos == -1 )
312 theUserName = aUserInfo;
314 else
316 theUserName = aUserInfo.copy( 0, nPos );
317 thePassWord = aUserInfo.copy( nPos + 1 );
321 catch ( DAVException const & )
323 // abort
324 return -1;
327 else
329 // username buffer is prefilled with user name from last attempt.
330 theUserName = rtl::OUString::createFromAscii( inoutUserName );
331 // @@@ Neon does not initialize password buffer (last checked: 0.22.0).
332 //thePassWord = rtl::OUString::createFromAscii( inoutPassWord );
335 bool bCanUseSystemCreds = false;
337 #ifdef NE_FEATURE_SSPI
338 bCanUseSystemCreds = (attempt == 0) && // avoid endless loops
339 ne_has_support( NE_FEATURE_SSPI ) && // Windows-only feature.
340 ( ne_strcasecmp( inAuthProtocol, "NTLM" ) == 0 ) ||
341 ( ne_strcasecmp( inAuthProtocol, "Negotiate" ) == 0 );
342 #endif
344 // #i97003# (tkr): Ask XMasterPasswordHandling if we should store the
345 // credentials persistently and give this information to the auth listener
346 uno::Reference< task::XMasterPasswordHandling > xMasterPasswordHandling;
349 xMasterPasswordHandling =
350 uno::Reference< task::XMasterPasswordHandling >(
351 theSession->getMSF()->createInstance(
352 rtl::OUString::createFromAscii(
353 "com.sun.star.task.PasswordContainer" )),
354 uno::UNO_QUERY );
356 catch ( uno::Exception const & )
360 int theRetVal = pListener->authenticate(
361 rtl::OUString::createFromAscii( inRealm ),
362 theSession->getHostName(),
363 theUserName,
364 thePassWord,
365 xMasterPasswordHandling.is()
366 ? xMasterPasswordHandling->
367 isPersistentStoringAllowed()
368 : sal_False,
369 bCanUseSystemCreds);
371 rtl::OString aUser(
372 rtl::OUStringToOString( theUserName, RTL_TEXTENCODING_UTF8 ) );
373 if ( aUser.getLength() > ( NE_ABUFSIZ - 1 ) )
375 OSL_ENSURE(
376 sal_False, "NeonSession_NeonAuth - username to long!" );
377 return -1;
380 rtl::OString aPass(
381 rtl::OUStringToOString( thePassWord, RTL_TEXTENCODING_UTF8 ) );
382 if ( aPass.getLength() > ( NE_ABUFSIZ - 1 ) )
384 OSL_ENSURE(
385 sal_False, "NeonSession_NeonAuth - password to long!" );
386 return -1;
389 strcpy( inoutUserName, // #100211# - checked
390 rtl::OUStringToOString( theUserName, RTL_TEXTENCODING_UTF8 ) );
392 strcpy( inoutPassWord, // #100211# - checked
393 rtl::OUStringToOString( thePassWord, RTL_TEXTENCODING_UTF8 ) );
395 return theRetVal;
398 // -------------------------------------------------------------------
400 namespace {
401 // -------------------------------------------------------------------
402 // Helper function
403 ::rtl::OUString GetHostnamePart( const ::rtl::OUString& _rRawString )
405 ::rtl::OUString sPart;
406 ::rtl::OUString sPartId = ::rtl::OUString::createFromAscii( "CN=" );
407 sal_Int32 nContStart = _rRawString.indexOf( sPartId );
408 if ( nContStart != -1 )
410 nContStart = nContStart + sPartId.getLength();
411 sal_Int32 nContEnd
412 = _rRawString.indexOf( sal_Unicode( ',' ), nContStart );
413 sPart = _rRawString.copy( nContStart, nContEnd - nContStart );
415 return sPart;
419 // -------------------------------------------------------------------
420 extern "C" int NeonSession_CertificationNotify( void *userdata,
421 int failures,
422 const ne_ssl_certificate *cert )
424 OSL_ASSERT( cert );
426 NeonSession * pSession = static_cast< NeonSession * >( userdata );
427 uno::Reference< security::XCertificateContainer > xCertificateContainer;
430 xCertificateContainer
431 = uno::Reference< security::XCertificateContainer >(
432 pSession->getMSF()->createInstance(
433 rtl::OUString::createFromAscii(
434 "com.sun.star.security.CertificateContainer" ) ),
435 uno::UNO_QUERY );
437 catch ( uno::Exception const & )
441 if ( !xCertificateContainer.is() )
442 return 1;
444 failures = 0;
446 char * dn = ne_ssl_readable_dname( ne_ssl_cert_subject( cert ) );
447 rtl::OUString cert_subject( dn, strlen( dn ), RTL_TEXTENCODING_UTF8, 0 );
449 free( dn );
451 security::CertificateContainerStatus certificateContainer(
452 xCertificateContainer->hasCertificate(
453 pSession->getHostName(), cert_subject ) );
455 if ( certificateContainer != security::CertificateContainerStatus_NOCERT )
456 return
457 certificateContainer == security::CertificateContainerStatus_TRUSTED
458 ? 0
459 : 1;
461 uno::Reference< xml::crypto::XSEInitializer > xSEInitializer;
464 xSEInitializer = uno::Reference< xml::crypto::XSEInitializer >(
465 pSession->getMSF()->createInstance(
466 rtl::OUString::createFromAscii( SEINITIALIZER_COMPONENT ) ),
467 uno::UNO_QUERY );
469 catch ( uno::Exception const & )
473 if ( !xSEInitializer.is() )
474 return 1;
476 uno::Reference< xml::crypto::XXMLSecurityContext > xSecurityContext(
477 xSEInitializer->createSecurityContext( rtl::OUString() ) );
479 uno::Reference< xml::crypto::XSecurityEnvironment > xSecurityEnv(
480 xSecurityContext->getSecurityEnvironment() );
482 //The end entity certificate
483 char * eeCertB64 = ne_ssl_cert_export( cert );
485 rtl::OString sEECertB64( eeCertB64 );
487 uno::Reference< com::sun::star::security::XCertificate > xEECert(
488 xSecurityEnv->createCertificateFromAscii(
489 rtl::OStringToOUString( sEECertB64, RTL_TEXTENCODING_ASCII_US ) ) );
491 ne_free( eeCertB64 );
492 eeCertB64 = 0;
494 std::vector< uno::Reference< security::XCertificate > > vecCerts;
495 const ne_ssl_certificate * issuerCert = cert;
498 //get the intermediate certificate
499 //the returned value is const ! Therfore it does not need to be freed
500 //with ne_ssl_cert_free, which takes a non-const argument
501 issuerCert = ne_ssl_cert_signedby( issuerCert );
502 if ( NULL == issuerCert )
503 break;
505 char * imCertB64 = ne_ssl_cert_export( issuerCert );
506 rtl::OString sInterMediateCertB64( imCertB64 );
507 ne_free( imCertB64 );
509 uno::Reference< security::XCertificate> xImCert(
510 xSecurityEnv->createCertificateFromAscii(
511 rtl::OStringToOUString(
512 sInterMediateCertB64, RTL_TEXTENCODING_ASCII_US ) ) );
513 if ( xImCert.is() )
514 vecCerts.push_back( xImCert );
516 while ( 1 );
518 sal_Int64 certValidity = xSecurityEnv->verifyCertificate( xEECert,
519 ::comphelper::containerToSequence( vecCerts ) );
521 if ( pSession->isDomainMatch(
522 GetHostnamePart( xEECert.get()->getSubjectName() ) ) )
524 // if host name matched with certificate then look if the
525 // certificate was ok
526 if( certValidity == security::CertificateValidity::VALID )
527 return 0;
530 const uno::Reference< ucb::XCommandEnvironment > xEnv(
531 pSession->getRequestEnvironment().m_xEnv );
532 if ( xEnv.is() )
534 failures = static_cast< int >( certValidity );
536 uno::Reference< task::XInteractionHandler > xIH(
537 xEnv->getInteractionHandler() );
538 if ( xIH.is() )
540 rtl::Reference< ucbhelper::SimpleCertificateValidationRequest >
541 xRequest( new ucbhelper::SimpleCertificateValidationRequest(
542 (sal_Int32)failures, xEECert, pSession->getHostName() ) );
543 xIH->handle( xRequest.get() );
545 rtl::Reference< ucbhelper::InteractionContinuation > xSelection
546 = xRequest->getSelection();
548 if ( xSelection.is() )
550 uno::Reference< task::XInteractionApprove > xApprove(
551 xSelection.get(), uno::UNO_QUERY );
552 if ( xApprove.is() )
554 xCertificateContainer->addCertificate(
555 pSession->getHostName(), cert_subject, sal_True );
556 return 0;
558 else
560 // Don't trust cert
561 xCertificateContainer->addCertificate(
562 pSession->getHostName(), cert_subject, sal_False );
563 return 1;
567 else
569 // Don't trust cert
570 xCertificateContainer->addCertificate(
571 pSession->getHostName(), cert_subject, sal_False );
572 return 1;
575 return 1;
578 NeonLockStore * NeonSession::s_aNeonLockStore = NULL;
580 // -------------------------------------------------------------------
581 extern "C" void NeonSession_PreSendRequest( ne_request * req,
582 void * userdata,
583 ne_buffer * headers )
585 // userdata -> value returned by 'create'
587 NeonSession * pSession = static_cast< NeonSession * >( userdata );
588 if ( pSession )
590 // If there is a proxy server in between, it shall never use
591 // cached data. We always want 'up-to-date' data.
592 ne_buffer_concat( headers, "Pragma: no-cache", EOL, NULL );
593 // alternative, but understoud by HTTP 1.1 servers only:
594 // ne_buffer_concat( headers, "Cache-Control: max-age=0", EOL, NULL );
596 const RequestDataMap * pRequestData
597 = static_cast< const RequestDataMap* >(
598 pSession->getRequestData() );
600 RequestDataMap::const_iterator it = pRequestData->find( req );
601 if ( it != pRequestData->end() )
603 if ( (*it).second.aContentType.getLength() )
605 char * pData = headers->data;
606 if ( strstr( pData, "Content-Type:" ) == NULL )
608 rtl::OString aType
609 = rtl::OUStringToOString( (*it).second.aContentType,
610 RTL_TEXTENCODING_UTF8 );
611 ne_buffer_concat( headers, "Content-Type: ",
612 aType.getStr(), EOL, NULL );
616 if ( (*it).second.aReferer.getLength() )
618 char * pData = headers->data;
619 if ( strstr( pData, "Referer:" ) == NULL )
621 rtl::OString aReferer
622 = rtl::OUStringToOString( (*it).second.aReferer,
623 RTL_TEXTENCODING_UTF8 );
624 ne_buffer_concat( headers, "Referer: ",
625 aReferer.getStr(), EOL, NULL );
630 const DAVRequestHeaders & rHeaders
631 = pSession->getRequestEnvironment().m_aRequestHeaders;
633 DAVRequestHeaders::const_iterator it1( rHeaders.begin() );
634 const DAVRequestHeaders::const_iterator end1( rHeaders.end() );
636 while ( it1 != end1 )
638 rtl::OString aHeader
639 = rtl::OUStringToOString( (*it1).first,
640 RTL_TEXTENCODING_UTF8 );
641 rtl::OString aValue
642 = rtl::OUStringToOString( (*it1).second,
643 RTL_TEXTENCODING_UTF8 );
644 ne_buffer_concat( headers, aHeader.getStr(), ": ",
645 aValue.getStr(), EOL, NULL );
647 ++it1;
651 } // namespace
653 // -------------------------------------------------------------------
654 // Constructor
655 // -------------------------------------------------------------------
656 NeonSession::NeonSession(
657 const rtl::Reference< DAVSessionFactory > & rSessionFactory,
658 const rtl::OUString& inUri,
659 const ucbhelper::InternetProxyDecider & rProxyDecider )
660 throw ( DAVException )
661 : DAVSession( rSessionFactory ),
662 m_pHttpSession( 0 ),
663 m_pRequestData( new RequestDataMap ),
664 m_rProxyDecider( rProxyDecider )
666 NeonUri theUri( inUri );
667 m_aScheme = theUri.GetScheme();
668 m_aHostName = theUri.GetHost();
669 m_nPort = theUri.GetPort();
670 m_aUserInfo = theUri.GetUserInfo();
672 // Init();
675 // -------------------------------------------------------------------
676 // Destructor
677 // -------------------------------------------------------------------
678 NeonSession::~NeonSession( )
680 if ( m_pHttpSession )
682 ne_session_destroy( m_pHttpSession );
683 m_pHttpSession = 0;
686 delete static_cast<RequestDataMap*>(m_pRequestData);
689 // -------------------------------------------------------------------
690 void NeonSession::Init()
691 throw ( DAVException )
693 osl::Guard< osl::Mutex > theGuard( m_aMutex );
695 bool bCreateNewSession = false;
697 if ( m_pHttpSession == 0 )
699 // Ensure that Neon sockets are initialize
701 // --> tkr #151111# crashed if copy and pasted pictures from the internet
702 // ne_sock_init() was executed by two threads at the same time.
703 osl::Guard< osl::Mutex > theGlobalGuard( m_aGlobalMutex );
704 // <--
705 if ( !m_bGlobalsInited )
707 if ( ne_sock_init() != 0 )
708 throw DAVException( DAVException::DAV_SESSION_CREATE,
709 NeonUri::makeConnectionEndPointString(
710 m_aHostName, m_nPort ) );
711 #if OSL_DEBUG_LEVEL > 0
712 ne_debug_init( stderr, NE_DBG_LOCKS );
713 #endif
714 // #122205# - libxml2 needs to be initialized once if used by
715 // multithreaded programs like OOo.
716 xmlInitParser();
717 m_bGlobalsInited = true;
720 const ucbhelper::InternetProxyServer & rProxyCfg = getProxySettings();
722 m_aProxyName = rProxyCfg.aName;
723 m_nProxyPort = rProxyCfg.nPort;
725 // Not yet initialized. Create new session.
726 bCreateNewSession = true;
728 else
730 // #112271# Check whether proxy settings are still valid (They may
731 // change at any time). If not, create new Neon session.
733 const ucbhelper::InternetProxyServer & rProxyCfg = getProxySettings();
735 if ( ( rProxyCfg.aName != m_aProxyName )
736 || ( rProxyCfg.nPort != m_nProxyPort ) )
738 m_aProxyName = rProxyCfg.aName;
739 m_nProxyPort = rProxyCfg.nPort;
741 // new session needed, destroy old first
742 ne_session_destroy( m_pHttpSession );
743 m_pHttpSession = 0;
744 bCreateNewSession = true;
748 if ( bCreateNewSession )
750 // @@@ For FTP over HTTP proxy inUserInfo is needed to be able to
751 // build the complete request URI (including user:pass), but
752 // currently (0.22.0) neon does not allow to pass the user info
753 // to the session
755 m_pHttpSession = ne_session_create(
756 rtl::OUStringToOString( m_aScheme,
757 RTL_TEXTENCODING_UTF8 ).getStr(),
758 /* theUri.GetUserInfo(),
759 @@@ for FTP via HTTP proxy, but not supported by Neon */
760 rtl::OUStringToOString( m_aHostName,
761 RTL_TEXTENCODING_UTF8 ).getStr(),
762 m_nPort );
764 if ( m_pHttpSession == 0 )
765 throw DAVException( DAVException::DAV_SESSION_CREATE,
766 NeonUri::makeConnectionEndPointString(
767 m_aHostName, m_nPort ) );
769 if (m_aScheme.equalsIgnoreAsciiCase( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
770 "https" ) ) ) )
773 // Get all trusted certificates from key store
777 // Set a failure callback for certificate check
778 ne_ssl_set_verify( m_pHttpSession, NeonSession_CertificationNotify, this);
781 // Add hooks (i.e. for adding additional headers to the request)
783 #if 0
784 /* Hook called when a request is created. */
785 //typedef void (*ne_create_request_fn)(ne_request *req, void *userdata,
786 // const char *method, const char *path);
788 ne_hook_create_request( m_pHttpSession, create_req_hook_fn, this );
789 #endif
791 /* Hook called before the request is sent. 'header' is the raw HTTP
792 * header before the trailing CRLF is added: add in more here. */
793 //typedef void (*ne_pre_send_fn)(ne_request *req, void *userdata,
794 // ne_buffer *header);
796 ne_hook_pre_send( m_pHttpSession, NeonSession_PreSendRequest, this );
797 #if 0
798 /* Hook called after the request is sent. May return:
799 * NE_OK everything is okay
800 * NE_RETRY try sending the request again.
801 * anything else signifies an error, and the request is failed. The
802 * return code is passed back the _dispatch caller, so the session error
803 * must also be set appropriately (ne_set_error).
805 //typedef int (*ne_post_send_fn)(ne_request *req, void *userdata,
806 // const ne_status *status);
808 ne_hook_post_send( m_pHttpSession, post_send_req_hook_fn, this );
810 /* Hook called when the request is destroyed. */
811 //typedef void (*ne_destroy_req_fn)(ne_request *req, void *userdata);
813 ne_hook_destroy_request( m_pHttpSession, destroy_req_hook_fn, this );
815 /* Hook called when the session is destroyed. */
816 //typedef void (*ne_destroy_sess_fn)(void *userdata);
818 ne_hook_destroy_session( m_pHttpSession, destroy_sess_hook_fn, this );
819 #endif
821 if ( m_aProxyName.getLength() )
823 ne_session_proxy( m_pHttpSession,
824 rtl::OUStringToOString( m_aProxyName,
825 RTL_TEXTENCODING_UTF8 )
826 .getStr(),
827 m_nProxyPort );
830 if ( !s_aNeonLockStore )
831 s_aNeonLockStore = ne_lockstore_create();
833 if ( s_aNeonLockStore == NULL )
834 throw DAVException( DAVException::DAV_SESSION_CREATE,
835 NeonUri::makeConnectionEndPointString( m_aHostName, m_nPort ) );
837 // Register the lock store
838 ne_lockstore_register( s_aNeonLockStore, m_pHttpSession );
840 // Register for redirects.
841 ne_redirect_register( m_pHttpSession );
843 // authentication callbacks.
844 #if NEON_VERSION >= 0x0260
845 ne_add_server_auth( m_pHttpSession, NE_AUTH_ALL, NeonSession_NeonAuth, this );
846 ne_add_proxy_auth ( m_pHttpSession, NE_AUTH_ALL, NeonSession_NeonAuth, this );
847 #else
848 ne_set_server_auth( m_pHttpSession, NeonSession_NeonAuth, this );
849 ne_set_proxy_auth ( m_pHttpSession, NeonSession_NeonAuth, this );
850 #endif
854 // -------------------------------------------------------------------
855 // virtual
856 sal_Bool NeonSession::CanUse( const rtl::OUString & inUri )
860 NeonUri theUri( inUri );
861 if ( ( theUri.GetPort() == m_nPort ) &&
862 ( theUri.GetHost() == m_aHostName ) &&
863 ( theUri.GetScheme() == m_aScheme ) )
864 return sal_True;
866 catch ( DAVException const & )
868 return sal_False;
870 return sal_False;
873 // -------------------------------------------------------------------
874 // virtual
875 sal_Bool NeonSession::UsesProxy()
877 Init();
878 return ( m_aProxyName.getLength() > 0 );
881 // -------------------------------------------------------------------
882 // OPTIONS
883 // -------------------------------------------------------------------
884 void NeonSession::OPTIONS( const rtl::OUString & inPath,
885 DAVCapabilities & outCapabilities,
886 const DAVRequestEnvironment & rEnv )
887 throw( DAVException )
889 osl::Guard< osl::Mutex > theGuard( m_aMutex );
891 Init();
893 m_aEnv = rEnv;
895 HttpServerCapabilities servercaps;
896 memset( &servercaps, 0, sizeof( servercaps ) );
898 int theRetVal = ne_options( m_pHttpSession,
899 rtl::OUStringToOString(
900 inPath, RTL_TEXTENCODING_UTF8 ),
901 &servercaps );
902 HandleError( theRetVal );
904 outCapabilities.class1 = !!servercaps.dav_class1;
905 outCapabilities.class2 = !!servercaps.dav_class2;
906 outCapabilities.executable = !!servercaps.dav_executable;
909 // -------------------------------------------------------------------
910 // PROPFIND - allprop & named
911 // -------------------------------------------------------------------
912 void NeonSession::PROPFIND( const rtl::OUString & inPath,
913 const Depth inDepth,
914 const std::vector< rtl::OUString > & inPropNames,
915 std::vector< DAVResource > & ioResources,
916 const DAVRequestEnvironment & rEnv )
917 throw ( DAVException )
919 osl::Guard< osl::Mutex > theGuard( m_aMutex );
921 Init();
923 m_aEnv = rEnv;
925 int theRetVal = NE_OK;
926 NeonPropFindRequest theRequest( m_pHttpSession,
927 rtl::OUStringToOString(
928 inPath, RTL_TEXTENCODING_UTF8 ),
929 inDepth,
930 inPropNames,
931 ioResources,
932 theRetVal );
933 HandleError( theRetVal );
936 // -------------------------------------------------------------------
937 // PROPFIND - propnames
938 // -------------------------------------------------------------------
939 void NeonSession::PROPFIND( const rtl::OUString & inPath,
940 const Depth inDepth,
941 std::vector< DAVResourceInfo >& ioResInfo,
942 const DAVRequestEnvironment & rEnv )
943 throw( DAVException )
945 osl::Guard< osl::Mutex > theGuard( m_aMutex );
947 Init();
949 m_aEnv = rEnv;
951 int theRetVal = NE_OK;
952 NeonPropFindRequest theRequest( m_pHttpSession,
953 rtl::OUStringToOString(
954 inPath, RTL_TEXTENCODING_UTF8 ),
955 inDepth,
956 ioResInfo,
957 theRetVal );
958 HandleError( theRetVal );
961 // -------------------------------------------------------------------
962 // PROPPATCH
963 // -------------------------------------------------------------------
964 void NeonSession::PROPPATCH( const rtl::OUString & inPath,
965 const std::vector< ProppatchValue > & inValues,
966 const DAVRequestEnvironment & rEnv )
967 throw( DAVException )
969 /* @@@ Which standard live properties can be set by the client?
970 This is a known WebDAV RFC issue ( verified: 04/10/2001 )
971 --> http://www.ics.uci.edu/pub/ietf/webdav/protocol/issues.html
973 mod_dav implementation:
975 creationdate r ( File System prop )
976 displayname w
977 getcontentlanguage r ( #ifdef DAV_DISABLE_WRITEABLE_PROPS )
978 getcontentlength r ( File System prop )
979 getcontenttype r ( #ifdef DAV_DISABLE_WRITEABLE_PROPS )
980 getetag r ( File System prop )
981 getlastmodified r ( File System prop )
982 lockdiscovery r
983 resourcetype r
984 source w
985 supportedlock r
986 executable w ( #ifndef WIN32 )
988 All dead properties are of course writable.
991 int theRetVal = NE_OK;
992 int n; // for the "for" loop
994 // Generate the list of properties we want to set.
995 int nPropCount = inValues.size();
996 ne_proppatch_operation* pItems
997 = new ne_proppatch_operation[ nPropCount + 1 ];
998 for ( n = 0; n < nPropCount; ++n )
1000 const ProppatchValue & rValue = inValues[ n ];
1002 // Split fullname into namespace and name!
1003 ne_propname * pName = new ne_propname;
1004 DAVProperties::createNeonPropName( rValue.name, *pName );
1005 pItems[ n ].name = pName;
1007 if ( rValue.operation == PROPSET )
1009 pItems[ n ].type = ne_propset;
1011 rtl::OUString aStringValue;
1012 if ( DAVProperties::isUCBDeadProperty( *pName ) )
1014 // DAV dead property added by WebDAV UCP?
1015 if ( !UCBDeadPropertyValue::toXML(
1016 rValue.value, aStringValue ) )
1018 // Error!
1019 pItems[ n ].value = 0;
1020 theRetVal = NE_ERROR;
1021 nPropCount = n + 1;
1022 break;
1025 else if ( !( rValue.value >>= aStringValue ) )
1027 // complex properties...
1028 if ( rValue.name == DAVProperties::SOURCE )
1030 uno::Sequence< ::com::sun::star::ucb::Link > aLinks;
1031 if ( rValue.value >>= aLinks )
1033 LinkSequence::toXML( aLinks, aStringValue );
1035 else
1037 // Error!
1038 pItems[ n ].value = 0;
1039 theRetVal = NE_ERROR;
1040 nPropCount = n + 1;
1041 break;
1044 else
1046 OSL_ENSURE( sal_False,
1047 "NeonSession::PROPPATCH - unsupported type!" );
1048 // Error!
1049 pItems[ n ].value = 0;
1050 theRetVal = NE_ERROR;
1051 nPropCount = n + 1;
1052 break;
1055 pItems[ n ].value
1056 = strdup( rtl::OUStringToOString( aStringValue,
1057 RTL_TEXTENCODING_UTF8 ) );
1059 else
1061 pItems[ n ].type = ne_propremove;
1062 pItems[ n ].value = 0;
1066 if ( theRetVal == NE_OK )
1068 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1070 Init();
1072 m_aEnv = rEnv;
1074 pItems[ n ].name = 0;
1076 theRetVal = ne_proppatch( m_pHttpSession,
1077 rtl::OUStringToOString(
1078 inPath, RTL_TEXTENCODING_UTF8 ),
1079 pItems );
1082 for ( n = 0; n < nPropCount; ++n )
1084 free( (void *)pItems[ n ].name->name );
1085 delete pItems[ n ].name;
1086 free( (void *)pItems[ n ].value );
1089 delete [] pItems;
1091 HandleError( theRetVal );
1094 // -------------------------------------------------------------------
1095 // HEAD
1096 // -------------------------------------------------------------------
1097 void NeonSession::HEAD( const ::rtl::OUString & inPath,
1098 const std::vector< ::rtl::OUString > & inHeaderNames,
1099 DAVResource & ioResource,
1100 const DAVRequestEnvironment & rEnv )
1101 throw( DAVException )
1103 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1105 Init();
1107 m_aEnv = rEnv;
1109 int theRetVal = NE_OK;
1110 NeonHeadRequest theRequest( m_pHttpSession,
1111 inPath,
1112 inHeaderNames,
1113 ioResource,
1114 theRetVal );
1115 HandleError( theRetVal );
1118 // -------------------------------------------------------------------
1119 // GET
1120 // -------------------------------------------------------------------
1121 uno::Reference< io::XInputStream >
1122 NeonSession::GET( const rtl::OUString & inPath,
1123 const DAVRequestEnvironment & rEnv )
1124 throw ( DAVException )
1126 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1128 Init();
1130 m_aEnv = rEnv;
1132 rtl::Reference< NeonInputStream > xInputStream( new NeonInputStream );
1133 NeonRequestContext aCtx( xInputStream );
1134 int theRetVal = GET( m_pHttpSession,
1135 rtl::OUStringToOString(
1136 inPath, RTL_TEXTENCODING_UTF8 ),
1137 NeonSession_ResponseBlockReader,
1138 false,
1139 &aCtx );
1140 HandleError( theRetVal );
1141 return uno::Reference< io::XInputStream >( xInputStream.get() );
1144 // -------------------------------------------------------------------
1145 // GET
1146 // -------------------------------------------------------------------
1147 void NeonSession::GET( const rtl::OUString & inPath,
1148 uno::Reference< io::XOutputStream > & ioOutputStream,
1149 const DAVRequestEnvironment & rEnv )
1150 throw ( DAVException )
1152 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1154 Init();
1156 m_aEnv = rEnv;
1158 NeonRequestContext aCtx( ioOutputStream );
1159 int theRetVal = GET( m_pHttpSession,
1160 rtl::OUStringToOString(
1161 inPath, RTL_TEXTENCODING_UTF8 ),
1162 NeonSession_ResponseBlockWriter,
1163 false,
1164 &aCtx );
1165 HandleError( theRetVal );
1168 // -------------------------------------------------------------------
1169 // GET
1170 // -------------------------------------------------------------------
1171 uno::Reference< io::XStream >
1172 NeonSession::GET( const rtl::OUString & inPath,
1173 const std::vector< ::rtl::OUString > & inHeaderNames,
1174 DAVResource & ioResource,
1175 const DAVRequestEnvironment & rEnv,
1176 sal_Bool bAllowEmpty )
1177 throw ( DAVException )
1179 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1181 Init();
1183 m_aEnv = rEnv;
1185 ioResource.uri = inPath;
1186 ioResource.properties.clear();
1188 rtl::Reference< NeonInputStream > xStream( new NeonInputStream );
1189 NeonRequestContext aCtx( xStream, inHeaderNames, ioResource );
1190 int theRetVal = GET( m_pHttpSession,
1191 rtl::OUStringToOString(
1192 inPath, RTL_TEXTENCODING_UTF8 ),
1193 NeonSession_ResponseBlockReader,
1194 true,
1195 &aCtx );
1196 try {
1197 HandleError( theRetVal );
1199 catch ( DAVException const & e )
1201 if ( !bAllowEmpty || ( e.getStatus() != SC_NOT_FOUND ) )
1202 throw;
1204 return uno::Reference< io::XStream >( xStream.get() );
1207 // -------------------------------------------------------------------
1208 // GET
1209 // -------------------------------------------------------------------
1210 void NeonSession::GET( const rtl::OUString & inPath,
1211 uno::Reference< io::XOutputStream > & ioOutputStream,
1212 const std::vector< ::rtl::OUString > & inHeaderNames,
1213 DAVResource & ioResource,
1214 const DAVRequestEnvironment & rEnv )
1215 throw ( DAVException )
1217 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1219 Init();
1221 m_aEnv = rEnv;
1223 ioResource.uri = inPath;
1224 ioResource.properties.clear();
1226 NeonRequestContext aCtx( ioOutputStream, inHeaderNames, ioResource );
1227 int theRetVal = GET( m_pHttpSession,
1228 rtl::OUStringToOString(
1229 inPath, RTL_TEXTENCODING_UTF8 ),
1230 NeonSession_ResponseBlockWriter,
1231 true,
1232 &aCtx );
1233 HandleError( theRetVal );
1236 // -------------------------------------------------------------------
1237 // PUT
1238 // -------------------------------------------------------------------
1239 void NeonSession::PUT( const rtl::OUString & inPath,
1240 const uno::Reference< io::XInputStream > & inInputStream,
1241 const DAVRequestEnvironment & rEnv )
1242 throw ( DAVException )
1244 // initialization etc. is performed in the other PUT
1246 uno::Sequence< sal_Int8 > aDataToSend;
1247 if ( !getDataFromInputStream( inInputStream, aDataToSend, false ) )
1248 throw DAVException( DAVException::DAV_INVALID_ARG );
1250 PUT( inPath,
1251 reinterpret_cast< const char * >( aDataToSend.getConstArray() ),
1252 aDataToSend.getLength(),
1253 rEnv );
1256 // -------------------------------------------------------------------
1257 // PUT
1258 // -------------------------------------------------------------------
1259 void NeonSession::PUT( const rtl::OUString &inPath,
1260 const char * buffer,
1261 size_t size,
1262 const DAVRequestEnvironment & rEnv )
1263 throw ( DAVException )
1265 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1267 Init();
1269 m_aEnv = rEnv;
1271 int theRetVal = PUT( m_pHttpSession,
1272 rtl::OUStringToOString(
1273 inPath, RTL_TEXTENCODING_UTF8 ),
1274 buffer,
1275 size );
1277 HandleError( theRetVal );
1280 // -------------------------------------------------------------------
1281 // POST
1282 // -------------------------------------------------------------------
1283 uno::Reference< io::XInputStream >
1284 NeonSession::POST( const rtl::OUString & inPath,
1285 const rtl::OUString & rContentType,
1286 const rtl::OUString & rReferer,
1287 const uno::Reference< io::XInputStream > & inInputStream,
1288 const DAVRequestEnvironment & rEnv )
1289 throw ( DAVException )
1291 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1293 uno::Sequence< sal_Int8 > aDataToSend;
1294 if ( !getDataFromInputStream( inInputStream, aDataToSend, true ) )
1295 throw DAVException( DAVException::DAV_INVALID_ARG );
1297 Init();
1299 m_aEnv = rEnv;
1301 rtl::Reference< NeonInputStream > xInputStream( new NeonInputStream );
1302 NeonRequestContext aCtx( xInputStream );
1303 int theRetVal = POST( m_pHttpSession,
1304 rtl::OUStringToOString(
1305 inPath, RTL_TEXTENCODING_UTF8 ),
1306 reinterpret_cast< const char * >(
1307 aDataToSend.getConstArray() ),
1308 NeonSession_ResponseBlockReader,
1309 &aCtx,
1310 rContentType,
1311 rReferer );
1313 HandleError( theRetVal );
1314 return uno::Reference< io::XInputStream >( xInputStream.get() );
1317 // -------------------------------------------------------------------
1318 // POST
1319 // -------------------------------------------------------------------
1320 void NeonSession::POST( const rtl::OUString & inPath,
1321 const rtl::OUString & rContentType,
1322 const rtl::OUString & rReferer,
1323 const uno::Reference< io::XInputStream > & inInputStream,
1324 uno::Reference< io::XOutputStream > & oOutputStream,
1325 const DAVRequestEnvironment & rEnv )
1326 throw ( DAVException )
1328 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1330 uno::Sequence< sal_Int8 > aDataToSend;
1331 if ( !getDataFromInputStream( inInputStream, aDataToSend, true ) )
1332 throw DAVException( DAVException::DAV_INVALID_ARG );
1334 Init();
1336 m_aEnv = rEnv;
1338 NeonRequestContext aCtx( oOutputStream );
1339 int theRetVal = POST( m_pHttpSession,
1340 rtl::OUStringToOString(
1341 inPath, RTL_TEXTENCODING_UTF8 ),
1342 reinterpret_cast< const char * >(
1343 aDataToSend.getConstArray() ),
1344 NeonSession_ResponseBlockWriter,
1345 &aCtx,
1346 rContentType,
1347 rReferer );
1349 HandleError( theRetVal );
1352 // -------------------------------------------------------------------
1353 // ABORT
1354 // -------------------------------------------------------------------
1355 void NeonSession::ABORT()
1356 throw ( DAVException )
1358 if (NULL !=m_pHttpSession)
1359 ne_close_connection(m_pHttpSession);
1362 // -------------------------------------------------------------------
1363 // MKCOL
1364 // -------------------------------------------------------------------
1365 void NeonSession::MKCOL( const rtl::OUString & inPath,
1366 const DAVRequestEnvironment & rEnv )
1367 throw ( DAVException )
1369 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1371 Init();
1373 m_aEnv = rEnv;
1375 int theRetVal = ne_mkcol( m_pHttpSession,
1376 rtl::OUStringToOString(
1377 inPath, RTL_TEXTENCODING_UTF8 ) );
1378 HandleError( theRetVal );
1381 // -------------------------------------------------------------------
1382 // COPY
1383 // -------------------------------------------------------------------
1384 void NeonSession::COPY( const rtl::OUString & inSourceURL,
1385 const rtl::OUString & inDestinationURL,
1386 const DAVRequestEnvironment & rEnv,
1387 sal_Bool inOverWrite )
1388 throw ( DAVException )
1390 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1392 Init();
1394 m_aEnv = rEnv;
1396 NeonUri theSourceUri( inSourceURL );
1397 NeonUri theDestinationUri( inDestinationURL );
1399 int theRetVal = ne_copy( m_pHttpSession,
1400 inOverWrite ? 1 : 0,
1401 NE_DEPTH_INFINITE,
1402 rtl::OUStringToOString(
1403 theSourceUri.GetPath(),
1404 RTL_TEXTENCODING_UTF8 ),
1405 rtl::OUStringToOString(
1406 theDestinationUri.GetPath(),
1407 RTL_TEXTENCODING_UTF8 ) );
1408 HandleError( theRetVal );
1411 // -------------------------------------------------------------------
1412 // MOVE
1413 // -------------------------------------------------------------------
1414 void NeonSession::MOVE( const rtl::OUString & inSourceURL,
1415 const rtl::OUString & inDestinationURL,
1416 const DAVRequestEnvironment & rEnv,
1417 sal_Bool inOverWrite )
1418 throw ( DAVException )
1420 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1422 Init();
1424 m_aEnv = rEnv;
1426 NeonUri theSourceUri( inSourceURL );
1427 NeonUri theDestinationUri( inDestinationURL );
1428 int theRetVal = ne_move( m_pHttpSession,
1429 inOverWrite ? 1 : 0,
1430 rtl::OUStringToOString(
1431 theSourceUri.GetPath(),
1432 RTL_TEXTENCODING_UTF8 ),
1433 rtl::OUStringToOString(
1434 theDestinationUri.GetPath(),
1435 RTL_TEXTENCODING_UTF8 ) );
1436 HandleError( theRetVal );
1439 // -------------------------------------------------------------------
1440 // DESTROY
1441 // -------------------------------------------------------------------
1442 void NeonSession::DESTROY( const rtl::OUString & inPath,
1443 const DAVRequestEnvironment & rEnv )
1444 throw ( DAVException )
1446 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1448 Init();
1450 m_aEnv = rEnv;
1452 int theRetVal = ne_delete( m_pHttpSession,
1453 rtl::OUStringToOString(
1454 inPath, RTL_TEXTENCODING_UTF8 ) );
1455 HandleError( theRetVal );
1458 // -------------------------------------------------------------------
1459 // LOCK
1460 // -------------------------------------------------------------------
1461 void NeonSession::LOCK( ucb::Lock & rLock,
1462 const DAVRequestEnvironment & rEnv )
1463 throw ( DAVException )
1465 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1467 Init();
1469 m_aEnv = rEnv;
1471 Lockit( rLock, true );
1474 // -------------------------------------------------------------------
1475 // UNLOCK
1476 // -------------------------------------------------------------------
1477 void NeonSession::UNLOCK( ucb::Lock & rLock,
1478 const DAVRequestEnvironment & rEnv )
1479 throw ( DAVException )
1481 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1483 Init();
1485 m_aEnv = rEnv;
1487 Lockit( rLock, false );
1490 // -------------------------------------------------------------------
1491 const ucbhelper::InternetProxyServer & NeonSession::getProxySettings() const
1493 if ( m_aScheme.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "http" ) ) ||
1494 m_aScheme.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "https" ) ) )
1496 return m_rProxyDecider.getProxy( m_aScheme,
1497 m_aHostName,
1498 m_nPort );
1500 else
1502 return m_rProxyDecider.getProxy( m_aScheme,
1503 rtl::OUString() /* not used */,
1504 -1 /* not used */ );
1508 // -------------------------------------------------------------------
1509 // HandleError
1510 // Common Error Handler
1511 // -------------------------------------------------------------------
1512 void NeonSession::HandleError( int nError )
1513 throw ( DAVException )
1515 m_aEnv = DAVRequestEnvironment();
1517 // Map error code to DAVException.
1518 switch ( nError )
1520 case NE_OK:
1521 // Cleanup.
1522 return;
1524 case NE_ERROR: // Generic error
1526 rtl::OUString aText = rtl::OUString::createFromAscii(
1527 ne_get_error( m_pHttpSession ) );
1528 #if OSL_DEBUG_LEVEL > 0
1529 fprintf( stderr, "WebDAV: got error '%s'\n", rtl::OUStringToOString( aText, RTL_TEXTENCODING_UTF8 ).getStr() );
1530 #endif
1531 throw DAVException( DAVException::DAV_HTTP_ERROR,
1532 aText,
1533 makeStatusCode( aText ) );
1536 case NE_LOOKUP: // Name lookup failed.
1537 throw DAVException( DAVException::DAV_HTTP_LOOKUP,
1538 NeonUri::makeConnectionEndPointString(
1539 m_aHostName, m_nPort ) );
1541 case NE_AUTH: // User authentication failed on server
1542 throw DAVException( DAVException::DAV_HTTP_AUTH,
1543 NeonUri::makeConnectionEndPointString(
1544 m_aHostName, m_nPort ) );
1546 case NE_PROXYAUTH: // User authentication failed on proxy
1547 throw DAVException( DAVException::DAV_HTTP_AUTHPROXY,
1548 NeonUri::makeConnectionEndPointString(
1549 m_aProxyName, m_nProxyPort ) );
1551 case NE_CONNECT: // Could not connect to server
1552 throw DAVException( DAVException::DAV_HTTP_CONNECT,
1553 NeonUri::makeConnectionEndPointString(
1554 m_aHostName, m_nPort ) );
1556 case NE_TIMEOUT: // Connection timed out
1557 throw DAVException( DAVException::DAV_HTTP_TIMEOUT,
1558 NeonUri::makeConnectionEndPointString(
1559 m_aHostName, m_nPort ) );
1561 case NE_FAILED: // The precondition failed
1562 throw DAVException( DAVException::DAV_HTTP_FAILED,
1563 NeonUri::makeConnectionEndPointString(
1564 m_aHostName, m_nPort ) );
1566 case NE_RETRY: // Retry request (ne_end_request ONLY)
1567 throw DAVException( DAVException::DAV_HTTP_RETRY,
1568 NeonUri::makeConnectionEndPointString(
1569 m_aHostName, m_nPort ) );
1571 case NE_REDIRECT:
1573 NeonUri aUri( ne_redirect_location( m_pHttpSession ) );
1574 throw DAVException(
1575 DAVException::DAV_HTTP_REDIRECT, aUri.GetURI() );
1577 default:
1579 OSL_TRACE( "NeonSession::HandleError : Unknown Neon error code!" );
1580 throw DAVException( DAVException::DAV_HTTP_ERROR,
1581 rtl::OUString::createFromAscii(
1582 ne_get_error( m_pHttpSession ) ) );
1587 void NeonSession::Lockit( ucb::Lock & rLock, bool bLockit )
1588 throw ( DAVException )
1590 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1592 if ( !s_aNeonLockStore )
1593 throw DAVException( DAVException::DAV_INVALID_ARG );
1595 ne_uri aUri;
1596 ne_uri_parse( rtl::OUStringToOString( m_aEnv.m_aRequestURI, RTL_TEXTENCODING_UTF8 ).getStr(),
1597 &aUri );
1599 #if NEON_VERSION < 0x0260
1600 #define FILLIN( field, val ) aUri.field = aUri.field? aUri.field: strdup( rtl::OUStringToOString( val, RTL_TEXTENCODING_UTF8 ).getStr() )
1601 FILLIN( scheme, m_aScheme );
1602 FILLIN( host, m_aHostName );
1603 aUri.port = aUri.port? aUri.port: m_nPort;
1604 #undef FILLIN
1605 #endif
1607 // Create the neon lock
1608 NeonLock * theLock = ne_lockstore_findbyuri( s_aNeonLockStore, &aUri );
1609 bool bAlreadyExists = false;
1610 if ( theLock )
1611 bAlreadyExists = true;
1612 else
1614 theLock = ne_lock_create();
1616 // Set the lock uri
1617 theLock->uri = aUri;
1619 // Set the lock depth
1620 switch( rLock.Depth )
1622 case ucb::LockDepth_ZERO: theLock->depth = NE_DEPTH_ZERO; break;
1623 case ucb::LockDepth_ONE: theLock->depth = NE_DEPTH_ONE; break;
1624 case ucb::LockDepth_INFINITY: theLock->depth = NE_DEPTH_INFINITE; break;
1625 default:
1626 throw DAVException( DAVException::DAV_INVALID_ARG );
1629 // Set the lock scope
1630 switch ( rLock.Scope )
1632 case ucb::LockScope_EXCLUSIVE: theLock->scope = ne_lockscope_exclusive; break;
1633 case ucb::LockScope_SHARED: theLock->scope = ne_lockscope_shared; break;
1634 default:
1635 throw DAVException( DAVException::DAV_INVALID_ARG );
1636 break;
1639 // Set the lock owner
1640 rtl::OUString aValue;
1641 rLock.Owner >>= aValue;
1643 theLock->owner = strdup( rtl::OUStringToOString( aValue, RTL_TEXTENCODING_UTF8 ).getStr() );
1645 // Set the lock timeout
1646 // We re-new the lock while the stream is open
1647 theLock->timeout = rLock.Timeout;
1650 if ( bLockit )
1652 int nRet;
1653 if ( bAlreadyExists )
1655 #if NEON_VERSION >= 0x0260
1656 nRet = ne_lock_refresh( m_pHttpSession, theLock );
1657 #else
1658 // workaround for a bug in neon 0.24
1659 // we have to call with a bigger structure that is used internally
1660 // and initialize parts of it
1662 struct lock_ctx
1664 struct ne_lock active; /* activelock */
1665 char *token; /* the token we're after. */
1666 int found;
1667 ne_buffer *cdata;
1670 struct lock_ctx ctx;
1672 memset( &ctx, 0, sizeof ctx );
1673 ctx.cdata = ne_buffer_create();
1675 memcpy( &ctx, theLock, sizeof( *theLock ) );
1676 nRet = ne_lock_refresh( m_pHttpSession, reinterpret_cast<NeonLock*>( &ctx ) );
1678 ne_buffer_destroy( ctx.cdata );
1679 #endif
1680 if ( ( nRet == NE_ERROR ) && strncmp (ne_get_error (m_pHttpSession), "No activelock ", strlen ("No activelock ")) == 0 )
1682 bAlreadyExists = false;
1683 ne_lockstore_remove( s_aNeonLockStore, theLock );
1686 if ( !bAlreadyExists )
1688 nRet = ne_lock( m_pHttpSession, theLock );
1690 if ( nRet == NE_OK )
1692 ne_lockstore_add( s_aNeonLockStore, theLock );
1694 uno::Sequence< rtl::OUString > aTokens( 1 );
1695 aTokens[0] = rtl::OUString::createFromAscii( theLock->token );
1696 rLock.LockTokens = aTokens;
1698 #if OSL_DEBUG_LEVEL > 0
1699 fprintf( stderr, "WebDAV: locked the URL, the token is: %s\n", theLock->token );
1700 #endif
1704 if ( ( nRet == NE_ERROR ) && getStatusCode( m_pHttpSession ) == SC_LOCKED )
1706 ucbhelper::cancelCommandExecution( ucb::IOErrorCode_LOCKING_VIOLATION,
1707 uno::Sequence< uno::Any >( 0 ), // FIXME more info about the file?
1708 m_aEnv.m_xEnv,
1709 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "a locking error occured" ) ),
1710 uno::Reference< ucb::XCommandProcessor >() );
1712 #if OSL_DEBUG_LEVEL > 0
1713 else if ( nRet == NE_OK )
1714 fprintf( stderr, "WebDAV: locked/refreshed lock OK\n" );
1715 else
1716 fprintf( stderr, "WebDAV: failed to lock the file: %s\n", ne_get_error( m_pHttpSession ) );
1717 #endif
1719 else
1721 // Set the lock token
1722 if ( rLock.LockTokens.getLength() > 0 )
1724 rtl::OUString theToken = rLock.LockTokens.getConstArray()[ 0 ];
1725 theLock->token = strdup( rtl::OUStringToOString( theToken, RTL_TEXTENCODING_UTF8 ).getStr() );
1727 #if OSL_DEBUG_LEVEL > 0
1728 fprintf( stderr, "WebDAV: going to unlock the URL, the token is: %s\n", theLock->token );
1729 #endif
1731 ne_unlock( m_pHttpSession, theLock );
1732 ne_lockstore_remove( s_aNeonLockStore, theLock );
1733 // FIXME even ne_lock_destroy( theLock )?
1738 // -------------------------------------------------------------------
1739 namespace {
1741 void runResponseHeaderHandler( void * userdata,
1742 const char * value )
1744 rtl::OUString aHeader( rtl::OUString::createFromAscii( value ) );
1745 sal_Int32 nPos = aHeader.indexOf( ':' );
1747 if ( nPos != -1 )
1749 rtl::OUString aHeaderName( aHeader.copy( 0, nPos ) );
1751 NeonRequestContext * pCtx
1752 = static_cast< NeonRequestContext * >( userdata );
1754 // Note: Empty vector means that all headers are requested.
1755 bool bIncludeIt = ( pCtx->pHeaderNames->size() == 0 );
1757 if ( !bIncludeIt )
1759 // Check whether this header was requested.
1760 std::vector< ::rtl::OUString >::const_iterator it(
1761 pCtx->pHeaderNames->begin() );
1762 const std::vector< ::rtl::OUString >::const_iterator end(
1763 pCtx->pHeaderNames->end() );
1765 while ( it != end )
1767 // header names are case insensitive
1768 if ( (*it).equalsIgnoreAsciiCase( aHeaderName ) )
1770 aHeaderName = (*it);
1771 break;
1773 ++it;
1776 if ( it != end )
1777 bIncludeIt = true;
1780 if ( bIncludeIt )
1782 // Create & set the PropertyValue
1783 DAVPropertyValue thePropertyValue;
1784 thePropertyValue.IsCaseSensitive = false;
1785 thePropertyValue.Name = aHeaderName;
1787 if ( nPos < aHeader.getLength() )
1788 thePropertyValue.Value <<= aHeader.copy( nPos + 1 ).trim();
1790 // Add the newly created PropertyValue
1791 pCtx->pResource->properties.push_back( thePropertyValue );
1796 } // namespace
1798 // -------------------------------------------------------------------
1799 // static
1800 int NeonSession::GET( ne_session * sess,
1801 const char * uri,
1802 ne_block_reader reader,
1803 bool getheaders,
1804 void * userdata )
1806 //struct get_context ctx;
1807 ne_request * req = ne_request_create( sess, "GET", uri );
1808 int ret;
1809 void *cursor = NULL;
1810 const char *name, *value;
1812 #if NEON_VERSION < 0x0250
1813 if ( getheaders )
1814 ne_add_response_header_catcher( req, runResponseHeaderHandler, userdata );
1815 #endif
1816 ne_add_response_body_reader( req, ne_accept_2xx, reader, userdata );
1818 ret = ne_request_dispatch( req );
1820 #if NEON_VERSION >= 0x0250
1821 if ( getheaders )
1823 while ((cursor = ne_response_header_iterate(req, cursor, &name, &value))
1824 != NULL)
1826 char buffer[8192];
1828 ne_snprintf(buffer, sizeof buffer, "%s: %s", name, value);
1830 runResponseHeaderHandler(userdata, buffer);
1833 #endif
1834 if ( ret == NE_OK && ne_get_status( req )->klass != 2 )
1835 ret = NE_ERROR;
1837 ne_request_destroy( req );
1838 return ret;
1841 // -------------------------------------------------------------------
1842 // static
1843 int NeonSession::PUT( ne_session * sess,
1844 const char * uri,
1845 const char * buffer,
1846 size_t size)
1848 ne_request * req = ne_request_create( sess, "PUT", uri );
1849 int ret;
1851 ne_lock_using_resource( req, uri, 0 );
1852 ne_lock_using_parent( req, uri );
1854 ne_set_request_body_buffer( req, buffer, size );
1856 ret = ne_request_dispatch( req );
1858 if ( ret == NE_OK && ne_get_status( req )->klass != 2 )
1859 ret = NE_ERROR;
1861 ne_request_destroy( req );
1862 return ret;
1865 // -------------------------------------------------------------------
1866 int NeonSession::POST( ne_session * sess,
1867 const char * uri,
1868 const char * buffer,
1869 ne_block_reader reader,
1870 void * userdata,
1871 const rtl::OUString & rContentType,
1872 const rtl::OUString & rReferer )
1874 ne_request * req = ne_request_create( sess, "POST", uri );
1875 //struct get_context ctx;
1876 int ret;
1878 RequestDataMap * pData = 0;
1880 if ( rContentType.getLength() || rReferer.getLength() )
1882 // Remember contenttype and referer. Data will be added to HTTP request
1883 // header in in 'PreSendRequest' callback.
1884 pData = static_cast< RequestDataMap* >( m_pRequestData );
1885 (*pData)[ req ] = RequestData( rContentType, rReferer );
1888 //ctx.total = -1;
1889 //ctx.fd = fd;
1890 //ctx.error = 0;
1891 //ctx.session = sess;
1893 ///* Read the value of the Content-Length header into ctx.total */
1894 //ne_add_response_header_handler( req, "Content-Length",
1895 // ne_handle_numeric_header, &ctx.total );
1897 ne_add_response_body_reader( req, ne_accept_2xx, reader, userdata );
1899 ne_set_request_body_buffer( req, buffer, strlen( buffer ) );
1901 ret = ne_request_dispatch( req );
1903 //if ( ctx.error )
1904 // ret = NE_ERROR;
1905 //else
1906 if ( ret == NE_OK && ne_get_status( req )->klass != 2 )
1907 ret = NE_ERROR;
1909 ne_request_destroy( req );
1911 if ( pData )
1913 // Remove request data from session's list.
1914 RequestDataMap::iterator it = pData->find( req );
1915 if ( it != pData->end() )
1916 pData->erase( it );
1919 return ret;
1922 // -------------------------------------------------------------------
1923 // static
1924 bool NeonSession::getDataFromInputStream(
1925 const uno::Reference< io::XInputStream > & xStream,
1926 uno::Sequence< sal_Int8 > & rData,
1927 bool bAppendTrailingZeroByte )
1929 if ( xStream.is() )
1931 uno::Reference< io::XSeekable > xSeekable( xStream, uno::UNO_QUERY );
1932 if ( xSeekable.is() )
1936 sal_Int32 nSize
1937 = sal::static_int_cast<sal_Int32>(xSeekable->getLength());
1938 sal_Int32 nRead
1939 = xStream->readBytes( rData, nSize );
1941 if ( nRead == nSize )
1943 if ( bAppendTrailingZeroByte )
1945 rData.realloc( nSize + 1 );
1946 rData[ nSize ] = sal_Int8( 0 );
1948 return true;
1951 catch ( io::NotConnectedException const & )
1953 // readBytes
1955 catch ( io::BufferSizeExceededException const & )
1957 // readBytes
1959 catch ( io::IOException const & )
1961 // getLength, readBytes
1964 else
1968 uno::Sequence< sal_Int8 > aBuffer;
1969 sal_Int32 nPos = 0;
1971 sal_Int32 nRead = xStream->readSomeBytes( aBuffer, 65536 );
1972 while ( nRead > 0 )
1974 if ( rData.getLength() < ( nPos + nRead ) )
1975 rData.realloc( nPos + nRead );
1977 aBuffer.realloc( nRead );
1978 rtl_copyMemory( (void*)( rData.getArray() + nPos ),
1979 (const void*)aBuffer.getConstArray(),
1980 nRead );
1981 nPos += nRead;
1983 aBuffer.realloc( 0 );
1984 nRead = xStream->readSomeBytes( aBuffer, 65536 );
1987 if ( bAppendTrailingZeroByte )
1989 rData.realloc( nPos + 1 );
1990 rData[ nPos ] = sal_Int8( 0 );
1992 return true;
1994 catch ( io::NotConnectedException const & )
1996 // readBytes
1998 catch ( io::BufferSizeExceededException const & )
2000 // readBytes
2002 catch ( io::IOException const & )
2004 // readBytes
2008 return false;
2010 // -------------------------------------------------------------------
2011 //static
2013 NeonSession::Map NeonSession::certMap;
2015 // ---------------------------------------------------------------------
2016 sal_Bool
2017 NeonSession::isDomainMatch( rtl::OUString certHostName)
2019 rtl::OUString hostName = getHostName();
2021 if (hostName.equalsIgnoreAsciiCase( certHostName ))
2022 return sal_True;
2026 if ( 0 == certHostName.indexOf( rtl::OUString::createFromAscii( "*" ) ) && hostName.getLength() >= certHostName.getLength() )
2028 rtl::OUString cmpStr = certHostName.copy( 1 );
2030 if ( hostName.matchIgnoreAsciiCase( cmpStr, hostName.getLength( ) - cmpStr.getLength()) )
2031 return sal_True;
2035 return sal_False;