update dev300-m58
[ooovba.git] / ucb / source / ucp / webdav / NeonSession.cxx
blob6dd822c35efa2cec2747e0fa12438508d71c685b
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"
47 #include "DAVAuthListener.hxx"
48 #include "NeonTypes.hxx"
49 #include "NeonSession.hxx"
50 #include "NeonInputStream.hxx"
51 #include "NeonPropFindRequest.hxx"
52 #include "NeonHeadRequest.hxx"
53 #include "NeonUri.hxx"
54 #ifndef _LINKSEQUENCE_HXX_
55 #include "LinkSequence.hxx"
56 #endif
58 #include <com/sun/star/xml/crypto/XSEInitializer.hpp>
59 #include "UCBDeadPropertyValue.hxx"
60 #include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
61 #include <com/sun/star/security/XCertificate.hpp>
62 #include <com/sun/star/security/CertificateValidity.hpp>
63 #include <com/sun/star/security/CertificateContainerStatus.hpp>
64 #include <com/sun/star/security/CertificateContainer.hpp>
65 #include <com/sun/star/security/XCertificateContainer.hpp>
66 #include <com/sun/star/task/XMasterPasswordHandling.hpp>
69 #ifndef _SIMPLECERTIFICATIONVALIDATIONREQUEST_HXX_
70 #include "ucbhelper/simplecertificatevalidationrequest.hxx"
71 #endif
72 #include <ucbhelper/cancelcommandexecution.hxx>
74 #include <cppuhelper/bootstrap.hxx>
77 using namespace com::sun::star;
78 using namespace webdav_ucp;
79 using namespace com::sun::star::security;
81 #define SEINITIALIZER_COMPONENT "com.sun.star.xml.crypto.SEInitializer"
83 #ifndef EOL
84 # define EOL "\r\n"
85 #endif
87 // -------------------------------------------------------------------
88 // RequestData
89 // -------------------------------------------------------------------
91 struct RequestData
93 // POST
94 rtl::OUString aContentType;
95 rtl::OUString aReferer;
97 RequestData() {}
98 RequestData( const rtl::OUString & rContentType,
99 const rtl::OUString & rReferer )
100 : aContentType( rContentType ), aReferer( rReferer ) {}
103 // -------------------------------------------------------------------
104 // RequestDataMap
105 // -------------------------------------------------------------------
107 struct equalPtr
109 bool operator()( const ne_request* p1, const ne_request* p2 ) const
111 return p1 == p2;
115 struct hashPtr
117 size_t operator()( const ne_request* p ) const
119 return (size_t)p;
123 typedef std::hash_map
125 ne_request*,
126 RequestData,
127 hashPtr,
128 equalPtr
130 RequestDataMap;
132 // -------------------------------------------------------------------
133 // static members!
134 bool NeonSession::m_bGlobalsInited = false;
135 osl::Mutex NeonSession::m_aGlobalMutex;
136 // -------------------------------------------------------------------
137 // Helper fuction
138 // -------------------------------------------------------------------
139 static sal_uInt16 makeStatusCode( const rtl::OUString & rStatusText )
141 // Extract status code from session error string. Unfortunately
142 // neon provides no direct access to the status code...
144 if ( rStatusText.getLength() < 3 )
146 OSL_ENSURE(
147 sal_False, "makeStatusCode - status text string to short!" );
148 return 0;
151 sal_Int32 nPos = rStatusText.indexOf( ' ' );
152 if ( nPos == -1 )
154 OSL_ENSURE( sal_False, "makeStatusCode - wrong status text format!" );
155 return 0;
158 return sal_uInt16( rStatusText.copy( 0, nPos ).toInt32() );
161 static sal_uInt16 getStatusCode( HttpSession *pSession )
163 rtl::OUString aText = rtl::OUString::createFromAscii( ne_get_error( pSession ) );
164 return makeStatusCode( aText );
167 // -------------------------------------------------------------------
168 struct NeonRequestContext
170 uno::Reference< io::XOutputStream > xOutputStream;
171 rtl::Reference< NeonInputStream > xInputStream;
172 const std::vector< ::rtl::OUString > * pHeaderNames;
173 DAVResource * pResource;
175 NeonRequestContext( uno::Reference< io::XOutputStream > & xOutStrm )
176 : xOutputStream( xOutStrm ), xInputStream( 0 ),
177 pHeaderNames( 0 ), pResource( 0 ) {}
179 NeonRequestContext( const rtl::Reference< NeonInputStream > & xInStrm )
180 : xOutputStream( 0 ), xInputStream( xInStrm ),
181 pHeaderNames( 0 ), pResource( 0 ) {}
183 NeonRequestContext( uno::Reference< io::XOutputStream > & xOutStrm,
184 const std::vector< ::rtl::OUString > & inHeaderNames,
185 DAVResource & ioResource )
186 : xOutputStream( xOutStrm ), xInputStream( 0 ),
187 pHeaderNames( &inHeaderNames ), pResource( &ioResource ) {}
189 NeonRequestContext( const rtl::Reference< NeonInputStream > & xInStrm,
190 const std::vector< ::rtl::OUString > & inHeaderNames,
191 DAVResource & ioResource )
192 : xOutputStream( 0 ), xInputStream( xInStrm ),
193 pHeaderNames( &inHeaderNames ), pResource( &ioResource ) {}
196 //--------------------------------------------------------------------
197 //--------------------------------------------------------------------
199 // Callback functions
201 //--------------------------------------------------------------------
202 //--------------------------------------------------------------------
204 // -------------------------------------------------------------------
205 // ResponseBlockReader
206 // A simple Neon response_block_reader for use with an XInputStream
207 // -------------------------------------------------------------------
209 #if NEON_VERSION >= 0x0250
210 extern "C" int
211 #else
212 extern "C" void
213 #endif
214 NeonSession_ResponseBlockReader( void * inUserData,
215 const char * inBuf,
216 size_t inLen )
218 // neon calls this function with (inLen == 0)...
219 if ( inLen > 0 )
221 NeonRequestContext * pCtx
222 = static_cast< NeonRequestContext * >( inUserData );
224 rtl::Reference< NeonInputStream > xInputStream(
225 pCtx->xInputStream);
227 if ( xInputStream.is() )
228 xInputStream->AddToStream( inBuf, inLen );
230 #if NEON_VERSION >= 0x0250
231 return 0;
232 #endif
235 // -------------------------------------------------------------------
236 // ResponseBlockWriter
237 // A simple Neon response_block_reader for use with an XOutputStream
238 // -------------------------------------------------------------------
240 #if NEON_VERSION >= 0x0250
241 extern "C" int
242 #else
243 extern "C" void
244 #endif
245 NeonSession_ResponseBlockWriter( void * inUserData,
246 const char * inBuf,
247 size_t inLen )
249 // neon calls this function with (inLen == 0)...
250 if ( inLen > 0 )
252 NeonRequestContext * pCtx
253 = static_cast< NeonRequestContext * >( inUserData );
254 uno::Reference< io::XOutputStream > xOutputStream
255 = pCtx->xOutputStream;
257 if ( xOutputStream.is() )
259 const uno::Sequence< sal_Int8 > aSeq( (sal_Int8 *)inBuf, inLen );
260 xOutputStream->writeBytes( aSeq );
263 #if NEON_VERSION >= 0x0250
264 return 0;
265 #endif
268 // -------------------------------------------------------------------
269 extern "C" int NeonSession_NeonAuth( void * inUserData,
270 const char * inRealm,
271 int attempt,
272 char * inoutUserName,
273 char * inoutPassWord )
275 /* The callback used to request the username and password in the given
276 * realm. The username and password must be copied into the buffers
277 * which are both of size NE_ABUFSIZ. The 'attempt' parameter is zero
278 * on the first call to the callback, and increases by one each time
279 * an attempt to authenticate fails.
281 * The callback must return zero to indicate that authentication
282 * should be attempted with the username/password, or non-zero to
283 * cancel the request. (if non-zero, username and password are
284 * ignored.) */
288 #if 0
289 // Give'em only a limited mumber of retries..
290 if ( attempt > 9 )
292 // abort
293 return -1;
295 #endif
297 NeonSession * theSession = static_cast< NeonSession * >( inUserData );
298 DAVAuthListener * pListener
299 = theSession->getRequestEnvironment().m_xAuthListener.get();
300 if ( !pListener )
302 // abort
303 return -1;
305 rtl::OUString theUserName;
306 rtl::OUString thePassWord;
308 if ( attempt == 0 )
310 // neon does not handle username supplied with request URI (for
311 // instance when doing FTP over proxy - last checked: 0.23.5 )
315 rtl::OUString aUserInfo( theSession->getUserInfo() );
316 if ( aUserInfo.getLength() )
318 sal_Int32 nPos = aUserInfo.indexOf( ':' );
319 if ( nPos == -1 )
321 theUserName = aUserInfo;
323 else
325 theUserName = aUserInfo.copy( 0, nPos );
326 thePassWord = aUserInfo.copy( nPos + 1 );
330 catch ( DAVException const & )
332 // abort
333 return -1;
336 else
338 // username buffer is prefilled with user name from last attempt.
339 theUserName = rtl::OUString::createFromAscii( inoutUserName );
340 // @@@ Neon does not initialize password buffer (last checked: 0.22.0).
341 //thePassWord = rtl::OUString::createFromAscii( inoutPassWord );
344 //i97003 (tkr): Ask XMasterPasswordHandling if we should store the credentials persistently and give this information to the SimpleAuthenticationRequest
345 uno::Reference< ::com::sun::star::task::XMasterPasswordHandling > xMasterPasswordHandling =
346 uno::Reference< ::com::sun::star::task::XMasterPasswordHandling >(
347 theSession->getMSF().get()->createInstance( rtl::OUString::createFromAscii( "com.sun.star.task.PasswordContainer" )), uno::UNO_QUERY );
348 // -
350 int theRetVal = pListener->authenticate(
351 rtl::OUString::createFromAscii( inRealm ),
352 theSession->getHostName(),
353 theUserName,
354 thePassWord,
355 xMasterPasswordHandling.is() ? xMasterPasswordHandling->isPersistentStoringAllowed() : sal_False);
357 rtl::OString aUser(
358 rtl::OUStringToOString( theUserName, RTL_TEXTENCODING_UTF8 ) );
359 if ( aUser.getLength() > ( NE_ABUFSIZ - 1 ) )
361 OSL_ENSURE(
362 sal_False, "NeonSession_NeonAuth - username to long!" );
363 return -1;
366 rtl::OString aPass(
367 rtl::OUStringToOString( thePassWord, RTL_TEXTENCODING_UTF8 ) );
368 if ( aPass.getLength() > ( NE_ABUFSIZ - 1 ) )
370 OSL_ENSURE(
371 sal_False, "NeonSession_NeonAuth - password to long!" );
372 return -1;
375 strcpy( inoutUserName, // #100211# - checked
376 rtl::OUStringToOString( theUserName, RTL_TEXTENCODING_UTF8 ) );
378 strcpy( inoutPassWord, // #100211# - checked
379 rtl::OUStringToOString( thePassWord, RTL_TEXTENCODING_UTF8 ) );
381 return theRetVal;
385 // -------------------------------------------------------------------
387 namespace {
388 // -------------------------------------------------------------------
389 // Helper function
390 ::rtl::OUString GetHostnamePart( const ::rtl::OUString& _rRawString )
392 ::rtl::OUString sPart;
393 ::rtl::OUString sPartId = ::rtl::OUString::createFromAscii( "CN=" );
394 sal_Int32 nContStart = _rRawString.indexOf( sPartId );
395 if ( nContStart != -1 )
397 nContStart = nContStart + sPartId.getLength();
398 sal_Int32 nContEnd = _rRawString.indexOf( sal_Unicode( ',' ), nContStart );
399 sPart = _rRawString.copy( nContStart, nContEnd - nContStart );
401 return sPart;
404 // -------------------------------------------------------------------
405 extern "C" int NeonSession_CertificationNotify( void *userdata,
406 int failures,
407 const ne_ssl_certificate *cert )
409 OSL_ASSERT(cert);
410 NeonSession * pSession = static_cast< NeonSession * >( userdata );
411 uno::Reference< ::com::sun::star::xml::crypto::XSecurityEnvironment > xSecurityEnv;
412 uno::Reference< ::com::sun::star::security::XCertificateContainer > xCertificateContainer;
415 xCertificateContainer = uno::Reference< ::com::sun::star::security::XCertificateContainer >(
416 pSession->getMSF().get()->createInstance( rtl::OUString::createFromAscii( "com.sun.star.security.CertificateContainer" )), uno::UNO_QUERY );
418 // YD if xmlsecurity is not built (os2), we cannot continue.
419 if (!xCertificateContainer.is())
420 return 1;
422 char * dn;
424 failures = 0;
426 dn = ne_ssl_readable_dname( ne_ssl_cert_subject( cert ) );
428 rtl::OUString cert_subject( dn, strlen( dn ), RTL_TEXTENCODING_UTF8, 0 );
430 free( dn );
432 CertificateContainerStatus certificateContainer;
433 certificateContainer = xCertificateContainer.get()->hasCertificate( pSession->getHostName(), cert_subject );
435 if( certificateContainer != CertificateContainerStatus_NOCERT )
437 if( certificateContainer == CertificateContainerStatus_TRUSTED )
438 return 0;
439 else
440 return 1;
443 rtl::OUString sSEInitializer;
444 ::com::sun::star::uno::Reference< com::sun::star::xml::crypto::XSEInitializer > mxSEInitializer;
445 ::com::sun::star::uno::Reference< com::sun::star::xml::crypto::XXMLSecurityContext > mxSecurityContext;
447 sSEInitializer = rtl::OUString::createFromAscii( SEINITIALIZER_COMPONENT );
448 mxSEInitializer = uno::Reference< com::sun::star::xml::crypto::XSEInitializer > (
449 pSession->getMSF().get()->createInstance( sSEInitializer ), uno::UNO_QUERY );
451 if ( mxSEInitializer.is() )
452 mxSecurityContext = mxSEInitializer->createSecurityContext( rtl::OUString::createFromAscii( "" ) );
454 xSecurityEnv = mxSecurityContext->getSecurityEnvironment();
457 //The end entity certificate
458 char * eeCertB64 = ne_ssl_cert_export( cert );
460 ::rtl::OString sEECertB64( eeCertB64 );
462 uno::Reference< com::sun::star::security::XCertificate> xEECert =
463 xSecurityEnv->createCertificateFromAscii(
464 ::rtl::OStringToOUString( sEECertB64, RTL_TEXTENCODING_ASCII_US ) );
466 free(eeCertB64);
467 eeCertB64 = NULL;
469 std::vector<uno::Reference<com::sun::star::security::XCertificate> > vecCerts;
470 const ne_ssl_certificate * issuerCert = cert;
473 //get the intermediate certificate
474 //the returned value is const ! Therfore it does not need to be freed
475 //with ne_ssl_cert_free, which takes a non-const argument
476 issuerCert = ne_ssl_cert_signedby(issuerCert);
477 if (NULL == issuerCert)
478 break;
480 char * imCertB64 = ne_ssl_cert_export(issuerCert);
481 ::rtl::OString sInterMediateCertB64(imCertB64);
482 free(imCertB64);
483 uno::Reference< com::sun::star::security::XCertificate> xImCert =
484 xSecurityEnv->createCertificateFromAscii(
485 ::rtl::OStringToOUString( sInterMediateCertB64, RTL_TEXTENCODING_ASCII_US ) );
486 if (xImCert.is())
487 vecCerts.push_back(xImCert);
488 }while (1);
490 sal_Int64 certValidity = xSecurityEnv->verifyCertificate( xEECert,
491 ::comphelper::containerToSequence(vecCerts) );
494 if ( pSession->isDomainMatch( GetHostnamePart( xEECert.get()->getSubjectName())) )
496 //if host name matched with certificate then look if the certificate was ok
497 if( certValidity == ::security::CertificateValidity::VALID )
498 return 0;
501 const uno::Reference< ucb::XCommandEnvironment > xEnv =
502 pSession->getRequestEnvironment().m_xEnv.get();
504 if ( xEnv.is() )
506 failures = static_cast<int>(certValidity);
508 uno::Reference< task::XInteractionHandler > xIH
509 = xEnv->getInteractionHandler();
510 if ( xIH.is() )
512 rtl::Reference< ucbhelper::SimpleCertificateValidationRequest > xRequest
513 = new ucbhelper::SimpleCertificateValidationRequest((sal_Int32)failures, xEECert, pSession->getHostName() );
514 xIH->handle( xRequest.get() );
516 rtl::Reference< ucbhelper::InteractionContinuation > xSelection
517 = xRequest->getSelection();
519 if ( xSelection.is() )
521 uno::Reference< task::XInteractionApprove > xApprove(
522 xSelection.get(), uno::UNO_QUERY );
523 if ( xApprove.is() )
525 xCertificateContainer->addCertificate(pSession->getHostName(), cert_subject, sal_True );
526 return 0;
527 } else {
528 // Dont trust Cert
529 xCertificateContainer->addCertificate(pSession->getHostName(), cert_subject, sal_False );
530 return 1;
534 } else
536 // Dont trust Cert
537 xCertificateContainer->addCertificate(pSession->getHostName(), cert_subject, sal_False );
538 return 1;
544 return 1;
546 // -------------------------------------------------------------------
547 extern "C" void NeonSession_PreSendRequest( ne_request * req,
548 void * userdata,
549 ne_buffer * headers )
551 // userdata -> value returned by 'create'
553 NeonSession * pSession = static_cast< NeonSession * >( userdata );
554 if ( pSession )
556 // If there is a proxy server in between, it shall never use
557 // cached data. We always want 'up-to-date' data.
558 ne_buffer_concat( headers, "Pragma: no-cache", EOL, NULL );
559 // alternative, but understoud by HTTP 1.1 servers only:
560 // ne_buffer_concat( headers, "Cache-Control: max-age=0", EOL, NULL );
562 const RequestDataMap * pRequestData
563 = static_cast< const RequestDataMap* >(
564 pSession->getRequestData() );
566 RequestDataMap::const_iterator it = pRequestData->find( req );
567 if ( it != pRequestData->end() )
569 if ( (*it).second.aContentType.getLength() )
571 char * pData = headers->data;
572 if ( strstr( pData, "Content-Type:" ) == NULL )
574 rtl::OString aType
575 = rtl::OUStringToOString( (*it).second.aContentType,
576 RTL_TEXTENCODING_UTF8 );
577 ne_buffer_concat( headers, "Content-Type: ",
578 aType.getStr(), EOL, NULL );
582 if ( (*it).second.aReferer.getLength() )
584 char * pData = headers->data;
585 if ( strstr( pData, "Referer:" ) == NULL )
587 rtl::OString aReferer
588 = rtl::OUStringToOString( (*it).second.aReferer,
589 RTL_TEXTENCODING_UTF8 );
590 ne_buffer_concat( headers, "Referer: ",
591 aReferer.getStr(), EOL, NULL );
596 const DAVRequestHeaders & rHeaders
597 = pSession->getRequestEnvironment().m_aRequestHeaders;
599 DAVRequestHeaders::const_iterator it1( rHeaders.begin() );
600 const DAVRequestHeaders::const_iterator end1( rHeaders.end() );
602 while ( it1 != end1 )
604 rtl::OString aHeader
605 = rtl::OUStringToOString( (*it1).first,
606 RTL_TEXTENCODING_UTF8 );
607 rtl::OString aValue
608 = rtl::OUStringToOString( (*it1).second,
609 RTL_TEXTENCODING_UTF8 );
610 ne_buffer_concat( headers, aHeader.getStr(), ": ",
611 aValue.getStr(), EOL, NULL );
613 ++it1;
618 NeonLockStore * NeonSession::s_aNeonLockStore = NULL;
620 // -------------------------------------------------------------------
621 // Constructor
622 // -------------------------------------------------------------------
623 NeonSession::NeonSession(
624 const rtl::Reference< DAVSessionFactory > & rSessionFactory,
625 const rtl::OUString& inUri,
626 const ucbhelper::InternetProxyDecider & rProxyDecider )
627 throw ( DAVException )
628 : DAVSession( rSessionFactory ),
629 m_pHttpSession( 0 ),
630 m_pRequestData( new RequestDataMap ),
631 m_rProxyDecider( rProxyDecider )
633 NeonUri theUri( inUri );
634 m_aScheme = theUri.GetScheme();
635 m_aHostName = theUri.GetHost();
636 m_nPort = theUri.GetPort();
637 m_aUserInfo = theUri.GetUserInfo();
639 // Init();
642 // -------------------------------------------------------------------
643 // Destructor
644 // -------------------------------------------------------------------
645 NeonSession::~NeonSession( )
647 if ( m_pHttpSession )
649 ne_session_destroy( m_pHttpSession );
650 m_pHttpSession = 0;
653 delete static_cast<RequestDataMap*>(m_pRequestData);
656 // -------------------------------------------------------------------
657 void NeonSession::Init()
658 throw ( DAVException )
660 osl::Guard< osl::Mutex > theGuard( m_aMutex );
662 bool bCreateNewSession = false;
664 if ( m_pHttpSession == 0 )
666 // Ensure that Neon sockets are initialize
668 // --> tkr #151111# crashed if copy and pasted pictures from the internet
669 // ne_sock_init() was executed by two threads at the same time.
670 osl::Guard< osl::Mutex > theGlobalGuard( m_aGlobalMutex );
671 // <--
672 if ( !m_bGlobalsInited )
674 if ( ne_sock_init() != 0 )
675 throw DAVException( DAVException::DAV_SESSION_CREATE,
676 NeonUri::makeConnectionEndPointString(
677 m_aHostName, m_nPort ) );
678 #if OSL_DEBUG_LEVEL > 0
679 ne_debug_init( stderr, NE_DBG_LOCKS );
680 #endif
681 // #122205# - libxml2 needs to be initialized once if used by
682 // multithreaded programs like OOo.
683 xmlInitParser();
684 m_bGlobalsInited = true;
687 const ucbhelper::InternetProxyServer & rProxyCfg = getProxySettings();
689 m_aProxyName = rProxyCfg.aName;
690 m_nProxyPort = rProxyCfg.nPort;
692 // Not yet initialized. Create new session.
693 bCreateNewSession = true;
695 else
697 // #112271# Check whether proxy settings are still valid (They may
698 // change at any time). If not, create new Neon session.
700 const ucbhelper::InternetProxyServer & rProxyCfg = getProxySettings();
702 if ( ( rProxyCfg.aName != m_aProxyName )
703 || ( rProxyCfg.nPort != m_nProxyPort ) )
705 m_aProxyName = rProxyCfg.aName;
706 m_nProxyPort = rProxyCfg.nPort;
708 // new session needed, destroy old first
709 ne_session_destroy( m_pHttpSession );
710 m_pHttpSession = 0;
711 bCreateNewSession = true;
715 if ( bCreateNewSession )
717 // @@@ For FTP over HTTP proxy inUserInfo is needed to be able to
718 // build the complete request URI (including user:pass), but
719 // currently (0.22.0) neon does not allow to pass the user info
720 // to the session
722 m_pHttpSession = ne_session_create(
723 rtl::OUStringToOString( m_aScheme,
724 RTL_TEXTENCODING_UTF8 ).getStr(),
725 /* theUri.GetUserInfo(),
726 @@@ for FTP via HTTP proxy, but not supported by Neon */
727 rtl::OUStringToOString( m_aHostName,
728 RTL_TEXTENCODING_UTF8 ).getStr(),
729 m_nPort );
731 if ( m_pHttpSession == 0 )
732 throw DAVException( DAVException::DAV_SESSION_CREATE,
733 NeonUri::makeConnectionEndPointString(
734 m_aHostName, m_nPort ) );
736 if (m_aScheme.equalsIgnoreAsciiCase( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
737 "https" ) ) ) )
740 // Get all trusted certificates from key store
744 // Set a failure callback for certificate check
745 ne_ssl_set_verify( m_pHttpSession, NeonSession_CertificationNotify, this);
748 // Add hooks (i.e. for adding additional headers to the request)
750 #if 0
751 /* Hook called when a request is created. */
752 //typedef void (*ne_create_request_fn)(ne_request *req, void *userdata,
753 // const char *method, const char *path);
755 ne_hook_create_request( m_pHttpSession, create_req_hook_fn, this );
756 #endif
758 /* Hook called before the request is sent. 'header' is the raw HTTP
759 * header before the trailing CRLF is added: add in more here. */
760 //typedef void (*ne_pre_send_fn)(ne_request *req, void *userdata,
761 // ne_buffer *header);
763 ne_hook_pre_send( m_pHttpSession, NeonSession_PreSendRequest, this );
765 #if 0
766 /* Hook called after the request is sent. May return:
767 * NE_OK everything is okay
768 * NE_RETRY try sending the request again.
769 * anything else signifies an error, and the request is failed. The
770 * return code is passed back the _dispatch caller, so the session error
771 * must also be set appropriately (ne_set_error).
773 //typedef int (*ne_post_send_fn)(ne_request *req, void *userdata,
774 // const ne_status *status);
776 ne_hook_post_send( m_pHttpSession, post_send_req_hook_fn, this );
778 /* Hook called when the request is destroyed. */
779 //typedef void (*ne_destroy_req_fn)(ne_request *req, void *userdata);
781 ne_hook_destroy_request( m_pHttpSession, destroy_req_hook_fn, this );
783 /* Hook called when the session is destroyed. */
784 //typedef void (*ne_destroy_sess_fn)(void *userdata);
786 ne_hook_destroy_session( m_pHttpSession, destroy_sess_hook_fn, this );
787 #endif
789 if ( m_aProxyName.getLength() )
791 ne_session_proxy( m_pHttpSession,
792 rtl::OUStringToOString( m_aProxyName,
793 RTL_TEXTENCODING_UTF8 )
794 .getStr(),
795 m_nProxyPort );
798 if ( !s_aNeonLockStore )
799 s_aNeonLockStore = ne_lockstore_create();
801 if ( s_aNeonLockStore == NULL )
802 throw DAVException( DAVException::DAV_SESSION_CREATE,
803 NeonUri::makeConnectionEndPointString( m_aHostName, m_nPort ) );
805 // Register the lock store
806 ne_lockstore_register( s_aNeonLockStore, m_pHttpSession );
808 // Register for redirects.
809 ne_redirect_register( m_pHttpSession );
811 // authentication callbacks.
813 // Note: Calling ne_set_[server|proxy]_auth more than once per
814 // m_pHttpSession instance sometimes(?) crashes Neon! ( last
815 // checked: 0.22.0)
816 #if NEON_VERSION >= 0x0260
817 ne_add_server_auth( m_pHttpSession, NE_AUTH_ALL, NeonSession_NeonAuth, this );
818 ne_add_proxy_auth ( m_pHttpSession, NE_AUTH_ALL, NeonSession_NeonAuth, this );
819 #else
820 ne_set_server_auth( m_pHttpSession, NeonSession_NeonAuth, this );
821 ne_set_proxy_auth ( m_pHttpSession, NeonSession_NeonAuth, this );
822 #endif
826 // -------------------------------------------------------------------
827 // virtual
828 sal_Bool NeonSession::CanUse( const rtl::OUString & inUri )
832 NeonUri theUri( inUri );
833 if ( ( theUri.GetPort() == m_nPort ) &&
834 ( theUri.GetHost() == m_aHostName ) &&
835 ( theUri.GetScheme() == m_aScheme ) )
836 return sal_True;
838 catch ( DAVException const & )
840 return sal_False;
842 return sal_False;
845 // -------------------------------------------------------------------
846 // virtual
847 sal_Bool NeonSession::UsesProxy()
849 Init();
850 return ( m_aProxyName.getLength() > 0 );
853 // -------------------------------------------------------------------
854 // OPTIONS
855 // -------------------------------------------------------------------
856 void NeonSession::OPTIONS( const rtl::OUString & inPath,
857 DAVCapabilities & outCapabilities,
858 const DAVRequestEnvironment & rEnv )
859 throw( DAVException )
861 osl::Guard< osl::Mutex > theGuard( m_aMutex );
863 Init();
865 m_aEnv = rEnv;
867 HttpServerCapabilities servercaps;
868 memset( &servercaps, 0, sizeof( servercaps ) );
870 int theRetVal = ne_options( m_pHttpSession,
871 rtl::OUStringToOString(
872 inPath, RTL_TEXTENCODING_UTF8 ),
873 &servercaps );
874 HandleError( theRetVal );
876 outCapabilities.class1 = !!servercaps.dav_class1;
877 outCapabilities.class2 = !!servercaps.dav_class2;
878 outCapabilities.executable = !!servercaps.dav_executable;
881 // -------------------------------------------------------------------
882 // PROPFIND - allprop & named
883 // -------------------------------------------------------------------
884 void NeonSession::PROPFIND( const rtl::OUString & inPath,
885 const Depth inDepth,
886 const std::vector< rtl::OUString > & inPropNames,
887 std::vector< DAVResource > & ioResources,
888 const DAVRequestEnvironment & rEnv )
889 throw ( DAVException )
891 osl::Guard< osl::Mutex > theGuard( m_aMutex );
893 Init();
895 m_aEnv = rEnv;
897 int theRetVal = NE_OK;
898 NeonPropFindRequest theRequest( m_pHttpSession,
899 rtl::OUStringToOString(
900 inPath, RTL_TEXTENCODING_UTF8 ),
901 inDepth,
902 inPropNames,
903 ioResources,
904 theRetVal );
905 HandleError( theRetVal );
908 // -------------------------------------------------------------------
909 // PROPFIND - propnames
910 // -------------------------------------------------------------------
911 void NeonSession::PROPFIND( const rtl::OUString & inPath,
912 const Depth inDepth,
913 std::vector< DAVResourceInfo >& ioResInfo,
914 const DAVRequestEnvironment & rEnv )
915 throw( DAVException )
917 osl::Guard< osl::Mutex > theGuard( m_aMutex );
919 Init();
921 m_aEnv = rEnv;
923 int theRetVal = NE_OK;
924 NeonPropFindRequest theRequest( m_pHttpSession,
925 rtl::OUStringToOString(
926 inPath, RTL_TEXTENCODING_UTF8 ),
927 inDepth,
928 ioResInfo,
929 theRetVal );
930 HandleError( theRetVal );
933 // -------------------------------------------------------------------
934 // PROPPATCH
935 // -------------------------------------------------------------------
936 void NeonSession::PROPPATCH( const rtl::OUString & inPath,
937 const std::vector< ProppatchValue > & inValues,
938 const DAVRequestEnvironment & rEnv )
939 throw( DAVException )
941 /* @@@ Which standard live properties can be set by the client?
942 This is a known WebDAV RFC issue ( verified: 04/10/2001 )
943 --> http://www.ics.uci.edu/pub/ietf/webdav/protocol/issues.html
945 mod_dav implementation:
947 creationdate r ( File System prop )
948 displayname w
949 getcontentlanguage r ( #ifdef DAV_DISABLE_WRITEABLE_PROPS )
950 getcontentlength r ( File System prop )
951 getcontenttype r ( #ifdef DAV_DISABLE_WRITEABLE_PROPS )
952 getetag r ( File System prop )
953 getlastmodified r ( File System prop )
954 lockdiscovery r
955 resourcetype r
956 source w
957 supportedlock r
958 executable w ( #ifndef WIN32 )
960 All dead properties are of course writable.
963 int theRetVal = NE_OK;
964 int n; // for the "for" loop
966 // Generate the list of properties we want to set.
967 int nPropCount = inValues.size();
968 ne_proppatch_operation* pItems
969 = new ne_proppatch_operation[ nPropCount + 1 ];
970 for ( n = 0; n < nPropCount; ++n )
972 const ProppatchValue & rValue = inValues[ n ];
974 // Split fullname into namespace and name!
975 ne_propname * pName = new ne_propname;
976 DAVProperties::createNeonPropName( rValue.name, *pName );
977 pItems[ n ].name = pName;
979 if ( rValue.operation == PROPSET )
981 pItems[ n ].type = ne_propset;
983 rtl::OUString aStringValue;
984 if ( DAVProperties::isUCBDeadProperty( *pName ) )
986 // DAV dead property added by WebDAV UCP?
987 if ( !UCBDeadPropertyValue::toXML(
988 rValue.value, aStringValue ) )
990 // Error!
991 pItems[ n ].value = 0;
992 theRetVal = NE_ERROR;
993 nPropCount = n + 1;
994 break;
997 else if ( !( rValue.value >>= aStringValue ) )
999 // complex properties...
1000 if ( rValue.name == DAVProperties::SOURCE )
1002 uno::Sequence< ::com::sun::star::ucb::Link > aLinks;
1003 if ( rValue.value >>= aLinks )
1005 LinkSequence::toXML( aLinks, aStringValue );
1007 else
1009 // Error!
1010 pItems[ n ].value = 0;
1011 theRetVal = NE_ERROR;
1012 nPropCount = n + 1;
1013 break;
1016 else
1018 OSL_ENSURE( sal_False,
1019 "NeonSession::PROPPATCH - unsupported type!" );
1020 // Error!
1021 pItems[ n ].value = 0;
1022 theRetVal = NE_ERROR;
1023 nPropCount = n + 1;
1024 break;
1027 pItems[ n ].value
1028 = strdup( rtl::OUStringToOString( aStringValue,
1029 RTL_TEXTENCODING_UTF8 ) );
1031 else
1033 pItems[ n ].type = ne_propremove;
1034 pItems[ n ].value = 0;
1038 if ( theRetVal == NE_OK )
1040 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1042 Init();
1044 m_aEnv = rEnv;
1046 pItems[ n ].name = 0;
1048 theRetVal = ne_proppatch( m_pHttpSession,
1049 rtl::OUStringToOString(
1050 inPath, RTL_TEXTENCODING_UTF8 ),
1051 pItems );
1054 for ( n = 0; n < nPropCount; ++n )
1056 free( (void *)pItems[ n ].name->name );
1057 delete pItems[ n ].name;
1058 free( (void *)pItems[ n ].value );
1061 delete [] pItems;
1063 HandleError( theRetVal );
1066 // -------------------------------------------------------------------
1067 // HEAD
1068 // -------------------------------------------------------------------
1069 void NeonSession::HEAD( const ::rtl::OUString & inPath,
1070 const std::vector< ::rtl::OUString > & inHeaderNames,
1071 DAVResource & ioResource,
1072 const DAVRequestEnvironment & rEnv )
1073 throw( DAVException )
1075 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1077 Init();
1079 m_aEnv = rEnv;
1081 int theRetVal = NE_OK;
1082 NeonHeadRequest theRequest( m_pHttpSession,
1083 inPath,
1084 inHeaderNames,
1085 ioResource,
1086 theRetVal );
1087 HandleError( theRetVal );
1090 // -------------------------------------------------------------------
1091 // GET
1092 // -------------------------------------------------------------------
1093 uno::Reference< io::XInputStream >
1094 NeonSession::GET( const rtl::OUString & inPath,
1095 const DAVRequestEnvironment & rEnv )
1096 throw ( DAVException )
1098 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1100 Init();
1102 m_aEnv = rEnv;
1104 rtl::Reference< NeonInputStream > xInputStream( new NeonInputStream );
1105 NeonRequestContext aCtx( xInputStream );
1106 int theRetVal = GET( m_pHttpSession,
1107 rtl::OUStringToOString(
1108 inPath, RTL_TEXTENCODING_UTF8 ),
1109 NeonSession_ResponseBlockReader,
1110 false,
1111 &aCtx );
1112 HandleError( theRetVal );
1113 return uno::Reference< io::XInputStream >( xInputStream.get() );
1116 // -------------------------------------------------------------------
1117 // GET
1118 // -------------------------------------------------------------------
1119 void NeonSession::GET( const rtl::OUString & inPath,
1120 uno::Reference< io::XOutputStream > & ioOutputStream,
1121 const DAVRequestEnvironment & rEnv )
1122 throw ( DAVException )
1124 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1126 Init();
1128 m_aEnv = rEnv;
1130 NeonRequestContext aCtx( ioOutputStream );
1131 int theRetVal = GET( m_pHttpSession,
1132 rtl::OUStringToOString(
1133 inPath, RTL_TEXTENCODING_UTF8 ),
1134 NeonSession_ResponseBlockWriter,
1135 false,
1136 &aCtx );
1137 HandleError( theRetVal );
1140 // -------------------------------------------------------------------
1141 // GET
1142 // -------------------------------------------------------------------
1143 uno::Reference< io::XStream >
1144 NeonSession::GET( const rtl::OUString & inPath,
1145 const std::vector< ::rtl::OUString > & inHeaderNames,
1146 DAVResource & ioResource,
1147 const DAVRequestEnvironment & rEnv,
1148 sal_Bool bAllowEmpty )
1149 throw ( DAVException )
1151 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1153 Init();
1155 m_aEnv = rEnv;
1157 ioResource.uri = inPath;
1158 ioResource.properties.clear();
1160 rtl::Reference< NeonInputStream > xStream( new NeonInputStream );
1161 NeonRequestContext aCtx( xStream, inHeaderNames, ioResource );
1162 int theRetVal = GET( m_pHttpSession,
1163 rtl::OUStringToOString(
1164 inPath, RTL_TEXTENCODING_UTF8 ),
1165 NeonSession_ResponseBlockReader,
1166 true,
1167 &aCtx );
1168 try {
1169 HandleError( theRetVal );
1171 catch ( DAVException const & e )
1173 if ( !bAllowEmpty || ( e.getStatus() != SC_NOT_FOUND ) )
1174 throw;
1176 return uno::Reference< io::XStream >( xStream.get() );
1179 // -------------------------------------------------------------------
1180 // GET
1181 // -------------------------------------------------------------------
1182 void NeonSession::GET( const rtl::OUString & inPath,
1183 uno::Reference< io::XOutputStream > & ioOutputStream,
1184 const std::vector< ::rtl::OUString > & inHeaderNames,
1185 DAVResource & ioResource,
1186 const DAVRequestEnvironment & rEnv )
1187 throw ( DAVException )
1189 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1191 Init();
1193 m_aEnv = rEnv;
1195 ioResource.uri = inPath;
1196 ioResource.properties.clear();
1198 NeonRequestContext aCtx( ioOutputStream, inHeaderNames, ioResource );
1199 int theRetVal = GET( m_pHttpSession,
1200 rtl::OUStringToOString(
1201 inPath, RTL_TEXTENCODING_UTF8 ),
1202 NeonSession_ResponseBlockWriter,
1203 true,
1204 &aCtx );
1205 HandleError( theRetVal );
1208 // -------------------------------------------------------------------
1209 // PUT
1210 // -------------------------------------------------------------------
1211 void NeonSession::PUT( const rtl::OUString & inPath,
1212 const uno::Reference< io::XInputStream > & inInputStream,
1213 const DAVRequestEnvironment & rEnv )
1214 throw ( DAVException )
1216 // initialization etc. is performed in the other PUT
1218 uno::Sequence< sal_Int8 > aDataToSend;
1219 if ( !getDataFromInputStream( inInputStream, aDataToSend, false ) )
1220 throw DAVException( DAVException::DAV_INVALID_ARG );
1222 PUT( inPath,
1223 reinterpret_cast< const char * >( aDataToSend.getConstArray() ),
1224 aDataToSend.getLength(),
1225 rEnv );
1228 // -------------------------------------------------------------------
1229 // PUT
1230 // -------------------------------------------------------------------
1231 void NeonSession::PUT( const rtl::OUString &inPath,
1232 const char * buffer,
1233 size_t size,
1234 const DAVRequestEnvironment & rEnv )
1235 throw ( DAVException )
1237 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1239 Init();
1241 m_aEnv = rEnv;
1243 int theRetVal = PUT( m_pHttpSession,
1244 rtl::OUStringToOString(
1245 inPath, RTL_TEXTENCODING_UTF8 ),
1246 buffer,
1247 size );
1249 HandleError( theRetVal );
1252 // -------------------------------------------------------------------
1253 // POST
1254 // -------------------------------------------------------------------
1255 uno::Reference< io::XInputStream >
1256 NeonSession::POST( const rtl::OUString & inPath,
1257 const rtl::OUString & rContentType,
1258 const rtl::OUString & rReferer,
1259 const uno::Reference< io::XInputStream > & inInputStream,
1260 const DAVRequestEnvironment & rEnv )
1261 throw ( DAVException )
1263 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1265 uno::Sequence< sal_Int8 > aDataToSend;
1266 if ( !getDataFromInputStream( inInputStream, aDataToSend, true ) )
1267 throw DAVException( DAVException::DAV_INVALID_ARG );
1269 Init();
1271 m_aEnv = rEnv;
1273 rtl::Reference< NeonInputStream > xInputStream( new NeonInputStream );
1274 NeonRequestContext aCtx( xInputStream );
1275 int theRetVal = POST( m_pHttpSession,
1276 rtl::OUStringToOString(
1277 inPath, RTL_TEXTENCODING_UTF8 ),
1278 reinterpret_cast< const char * >(
1279 aDataToSend.getConstArray() ),
1280 NeonSession_ResponseBlockReader,
1281 &aCtx,
1282 rContentType,
1283 rReferer );
1285 HandleError( theRetVal );
1286 return uno::Reference< io::XInputStream >( xInputStream.get() );
1289 // -------------------------------------------------------------------
1290 // POST
1291 // -------------------------------------------------------------------
1292 void NeonSession::POST( const rtl::OUString & inPath,
1293 const rtl::OUString & rContentType,
1294 const rtl::OUString & rReferer,
1295 const uno::Reference< io::XInputStream > & inInputStream,
1296 uno::Reference< io::XOutputStream > & oOutputStream,
1297 const DAVRequestEnvironment & rEnv )
1298 throw ( DAVException )
1300 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1302 uno::Sequence< sal_Int8 > aDataToSend;
1303 if ( !getDataFromInputStream( inInputStream, aDataToSend, true ) )
1304 throw DAVException( DAVException::DAV_INVALID_ARG );
1306 Init();
1308 m_aEnv = rEnv;
1310 NeonRequestContext aCtx( oOutputStream );
1311 int theRetVal = POST( m_pHttpSession,
1312 rtl::OUStringToOString(
1313 inPath, RTL_TEXTENCODING_UTF8 ),
1314 reinterpret_cast< const char * >(
1315 aDataToSend.getConstArray() ),
1316 NeonSession_ResponseBlockWriter,
1317 &aCtx,
1318 rContentType,
1319 rReferer );
1321 HandleError( theRetVal );
1324 // -------------------------------------------------------------------
1325 // ABORT
1326 // -------------------------------------------------------------------
1327 void NeonSession::ABORT()
1328 throw ( DAVException )
1330 if (NULL !=m_pHttpSession)
1331 ne_close_connection(m_pHttpSession);
1334 // -------------------------------------------------------------------
1335 // MKCOL
1336 // -------------------------------------------------------------------
1337 void NeonSession::MKCOL( const rtl::OUString & inPath,
1338 const DAVRequestEnvironment & rEnv )
1339 throw ( DAVException )
1341 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1343 Init();
1345 m_aEnv = rEnv;
1347 int theRetVal = ne_mkcol( m_pHttpSession,
1348 rtl::OUStringToOString(
1349 inPath, RTL_TEXTENCODING_UTF8 ) );
1350 HandleError( theRetVal );
1353 // -------------------------------------------------------------------
1354 // COPY
1355 // -------------------------------------------------------------------
1356 void NeonSession::COPY( const rtl::OUString & inSourceURL,
1357 const rtl::OUString & inDestinationURL,
1358 const DAVRequestEnvironment & rEnv,
1359 sal_Bool inOverWrite )
1360 throw ( DAVException )
1362 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1364 Init();
1366 m_aEnv = rEnv;
1368 NeonUri theSourceUri( inSourceURL );
1369 NeonUri theDestinationUri( inDestinationURL );
1371 int theRetVal = ne_copy( m_pHttpSession,
1372 inOverWrite ? 1 : 0,
1373 NE_DEPTH_INFINITE,
1374 rtl::OUStringToOString(
1375 theSourceUri.GetPath(),
1376 RTL_TEXTENCODING_UTF8 ),
1377 rtl::OUStringToOString(
1378 theDestinationUri.GetPath(),
1379 RTL_TEXTENCODING_UTF8 ) );
1380 HandleError( theRetVal );
1383 // -------------------------------------------------------------------
1384 // MOVE
1385 // -------------------------------------------------------------------
1386 void NeonSession::MOVE( const rtl::OUString & inSourceURL,
1387 const rtl::OUString & inDestinationURL,
1388 const DAVRequestEnvironment & rEnv,
1389 sal_Bool inOverWrite )
1390 throw ( DAVException )
1392 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1394 Init();
1396 m_aEnv = rEnv;
1398 NeonUri theSourceUri( inSourceURL );
1399 NeonUri theDestinationUri( inDestinationURL );
1400 int theRetVal = ne_move( m_pHttpSession,
1401 inOverWrite ? 1 : 0,
1402 rtl::OUStringToOString(
1403 theSourceUri.GetPath(),
1404 RTL_TEXTENCODING_UTF8 ),
1405 rtl::OUStringToOString(
1406 theDestinationUri.GetPath(),
1407 RTL_TEXTENCODING_UTF8 ) );
1408 HandleError( theRetVal );
1411 // -------------------------------------------------------------------
1412 // DESTROY
1413 // -------------------------------------------------------------------
1414 void NeonSession::DESTROY( const rtl::OUString & inPath,
1415 const DAVRequestEnvironment & rEnv )
1416 throw ( DAVException )
1418 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1420 Init();
1422 m_aEnv = rEnv;
1424 int theRetVal = ne_delete( m_pHttpSession,
1425 rtl::OUStringToOString(
1426 inPath, RTL_TEXTENCODING_UTF8 ) );
1427 HandleError( theRetVal );
1430 // -------------------------------------------------------------------
1431 // LOCK
1432 // -------------------------------------------------------------------
1433 void NeonSession::LOCK( ucb::Lock & rLock,
1434 const DAVRequestEnvironment & rEnv )
1435 throw ( DAVException )
1437 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1439 Init();
1441 m_aEnv = rEnv;
1443 Lockit( rLock, true );
1446 // -------------------------------------------------------------------
1447 // UNLOCK
1448 // -------------------------------------------------------------------
1449 void NeonSession::UNLOCK( ucb::Lock & rLock,
1450 const DAVRequestEnvironment & rEnv )
1451 throw ( DAVException )
1453 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1455 Init();
1457 m_aEnv = rEnv;
1459 Lockit( rLock, false );
1462 // -------------------------------------------------------------------
1463 const ucbhelper::InternetProxyServer & NeonSession::getProxySettings() const
1465 if ( m_aScheme.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "http" ) ) ||
1466 m_aScheme.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "https" ) ) )
1468 return m_rProxyDecider.getProxy( m_aScheme,
1469 m_aHostName,
1470 m_nPort );
1472 else
1474 return m_rProxyDecider.getProxy( m_aScheme,
1475 rtl::OUString() /* not used */,
1476 -1 /* not used */ );
1480 // -------------------------------------------------------------------
1481 // HandleError
1482 // Common Error Handler
1483 // -------------------------------------------------------------------
1484 void NeonSession::HandleError( int nError )
1485 throw ( DAVException )
1487 m_aEnv = DAVRequestEnvironment();
1489 // Map error code to DAVException.
1490 switch ( nError )
1492 case NE_OK:
1493 // Cleanup.
1494 return;
1496 case NE_ERROR: // Generic error
1498 rtl::OUString aText = rtl::OUString::createFromAscii(
1499 ne_get_error( m_pHttpSession ) );
1500 #if OSL_DEBUG_LEVEL > 0
1501 fprintf( stderr, "WebDAV: got error '%s'\n", rtl::OUStringToOString( aText, RTL_TEXTENCODING_UTF8 ).getStr() );
1502 #endif
1503 throw DAVException( DAVException::DAV_HTTP_ERROR,
1504 aText,
1505 makeStatusCode( aText ) );
1508 case NE_LOOKUP: // Name lookup failed.
1509 throw DAVException( DAVException::DAV_HTTP_LOOKUP,
1510 NeonUri::makeConnectionEndPointString(
1511 m_aHostName, m_nPort ) );
1513 case NE_AUTH: // User authentication failed on server
1514 throw DAVException( DAVException::DAV_HTTP_AUTH,
1515 NeonUri::makeConnectionEndPointString(
1516 m_aHostName, m_nPort ) );
1518 case NE_PROXYAUTH: // User authentication failed on proxy
1519 throw DAVException( DAVException::DAV_HTTP_AUTHPROXY,
1520 NeonUri::makeConnectionEndPointString(
1521 m_aProxyName, m_nProxyPort ) );
1523 case NE_CONNECT: // Could not connect to server
1524 throw DAVException( DAVException::DAV_HTTP_CONNECT,
1525 NeonUri::makeConnectionEndPointString(
1526 m_aHostName, m_nPort ) );
1528 case NE_TIMEOUT: // Connection timed out
1529 throw DAVException( DAVException::DAV_HTTP_TIMEOUT,
1530 NeonUri::makeConnectionEndPointString(
1531 m_aHostName, m_nPort ) );
1533 case NE_FAILED: // The precondition failed
1534 throw DAVException( DAVException::DAV_HTTP_FAILED,
1535 NeonUri::makeConnectionEndPointString(
1536 m_aHostName, m_nPort ) );
1538 case NE_RETRY: // Retry request (ne_end_request ONLY)
1539 throw DAVException( DAVException::DAV_HTTP_RETRY,
1540 NeonUri::makeConnectionEndPointString(
1541 m_aHostName, m_nPort ) );
1543 case NE_REDIRECT:
1545 NeonUri aUri( ne_redirect_location( m_pHttpSession ) );
1546 throw DAVException(
1547 DAVException::DAV_HTTP_REDIRECT, aUri.GetURI() );
1549 default:
1551 OSL_TRACE( "NeonSession::HandleError : Unknown Neon error code!" );
1552 throw DAVException( DAVException::DAV_HTTP_ERROR,
1553 rtl::OUString::createFromAscii(
1554 ne_get_error( m_pHttpSession ) ) );
1559 void NeonSession::Lockit( ucb::Lock & rLock, bool bLockit )
1560 throw ( DAVException )
1562 osl::Guard< osl::Mutex > theGuard( m_aMutex );
1564 if ( !s_aNeonLockStore )
1565 throw DAVException( DAVException::DAV_INVALID_ARG );
1567 ne_uri aUri;
1568 ne_uri_parse( rtl::OUStringToOString( m_aEnv.m_aRequestURI, RTL_TEXTENCODING_UTF8 ).getStr(),
1569 &aUri );
1571 #if NEON_VERSION < 0x0260
1572 #define FILLIN( field, val ) aUri.field = aUri.field? aUri.field: strdup( rtl::OUStringToOString( val, RTL_TEXTENCODING_UTF8 ).getStr() )
1573 FILLIN( scheme, m_aScheme );
1574 FILLIN( host, m_aHostName );
1575 aUri.port = aUri.port? aUri.port: m_nPort;
1576 #undef FILLIN
1577 #endif
1579 // Create the neon lock
1580 NeonLock * theLock = ne_lockstore_findbyuri( s_aNeonLockStore, &aUri );
1581 bool bAlreadyExists = false;
1582 if ( theLock )
1583 bAlreadyExists = true;
1584 else
1586 theLock = ne_lock_create();
1588 // Set the lock uri
1589 theLock->uri = aUri;
1591 // Set the lock depth
1592 switch( rLock.Depth )
1594 case ucb::LockDepth_ZERO: theLock->depth = NE_DEPTH_ZERO; break;
1595 case ucb::LockDepth_ONE: theLock->depth = NE_DEPTH_ONE; break;
1596 case ucb::LockDepth_INFINITY: theLock->depth = NE_DEPTH_INFINITE; break;
1597 default:
1598 throw DAVException( DAVException::DAV_INVALID_ARG );
1601 // Set the lock scope
1602 switch ( rLock.Scope )
1604 case ucb::LockScope_EXCLUSIVE: theLock->scope = ne_lockscope_exclusive; break;
1605 case ucb::LockScope_SHARED: theLock->scope = ne_lockscope_shared; break;
1606 default:
1607 throw DAVException( DAVException::DAV_INVALID_ARG );
1608 break;
1611 // Set the lock owner
1612 rtl::OUString aValue;
1613 rLock.Owner >>= aValue;
1615 theLock->owner = strdup( rtl::OUStringToOString( aValue, RTL_TEXTENCODING_UTF8 ).getStr() );
1617 // Set the lock timeout
1618 // We re-new the lock while the stream is open
1619 theLock->timeout = rLock.Timeout;
1622 if ( bLockit )
1624 int nRet;
1625 if ( bAlreadyExists )
1627 #if NEON_VERSION >= 0x0260
1628 nRet = ne_lock_refresh( m_pHttpSession, theLock );
1629 #else
1630 // workaround for a bug in neon 0.24
1631 // we have to call with a bigger structure that is used internally
1632 // and initialize parts of it
1634 struct lock_ctx
1636 struct ne_lock active; /* activelock */
1637 char *token; /* the token we're after. */
1638 int found;
1639 ne_buffer *cdata;
1642 struct lock_ctx ctx;
1644 memset( &ctx, 0, sizeof ctx );
1645 ctx.cdata = ne_buffer_create();
1647 memcpy( &ctx, theLock, sizeof( *theLock ) );
1648 nRet = ne_lock_refresh( m_pHttpSession, reinterpret_cast<NeonLock*>( &ctx ) );
1650 ne_buffer_destroy( ctx.cdata );
1651 #endif
1652 if ( ( nRet == NE_ERROR ) && strncmp (ne_get_error (m_pHttpSession), "No activelock ", strlen ("No activelock ")) == 0 )
1654 bAlreadyExists = false;
1655 ne_lockstore_remove( s_aNeonLockStore, theLock );
1658 if ( !bAlreadyExists )
1660 nRet = ne_lock( m_pHttpSession, theLock );
1662 if ( nRet == NE_OK )
1664 ne_lockstore_add( s_aNeonLockStore, theLock );
1666 uno::Sequence< rtl::OUString > aTokens( 1 );
1667 aTokens[0] = rtl::OUString::createFromAscii( theLock->token );
1668 rLock.LockTokens = aTokens;
1670 #if OSL_DEBUG_LEVEL > 0
1671 fprintf( stderr, "WebDAV: locked the URL, the token is: %s\n", theLock->token );
1672 #endif
1676 if ( ( nRet == NE_ERROR ) && getStatusCode( m_pHttpSession ) == SC_LOCKED )
1678 ucbhelper::cancelCommandExecution( ucb::IOErrorCode_LOCKING_VIOLATION,
1679 uno::Sequence< uno::Any >( 0 ), // FIXME more info about the file?
1680 m_aEnv.m_xEnv,
1681 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "a locking error occured" ) ),
1682 uno::Reference< ucb::XCommandProcessor >() );
1684 #if OSL_DEBUG_LEVEL > 0
1685 else if ( nRet == NE_OK )
1686 fprintf( stderr, "WebDAV: locked/refreshed lock OK\n" );
1687 else
1688 fprintf( stderr, "WebDAV: failed to lock the file: %s\n", ne_get_error( m_pHttpSession ) );
1689 #endif
1691 else
1693 // Set the lock token
1694 if ( rLock.LockTokens.getLength() > 0 )
1696 rtl::OUString theToken = rLock.LockTokens.getConstArray()[ 0 ];
1697 theLock->token = strdup( rtl::OUStringToOString( theToken, RTL_TEXTENCODING_UTF8 ).getStr() );
1699 #if OSL_DEBUG_LEVEL > 0
1700 fprintf( stderr, "WebDAV: going to unlock the URL, the token is: %s\n", theLock->token );
1701 #endif
1703 ne_unlock( m_pHttpSession, theLock );
1704 ne_lockstore_remove( s_aNeonLockStore, theLock );
1705 // FIXME even ne_lock_destroy( theLock )?
1710 // -------------------------------------------------------------------
1711 namespace {
1713 void runResponseHeaderHandler( void * userdata,
1714 const char * value )
1716 rtl::OUString aHeader( rtl::OUString::createFromAscii( value ) );
1717 sal_Int32 nPos = aHeader.indexOf( ':' );
1719 if ( nPos != -1 )
1721 rtl::OUString aHeaderName( aHeader.copy( 0, nPos ) );
1723 NeonRequestContext * pCtx
1724 = static_cast< NeonRequestContext * >( userdata );
1726 // Note: Empty vector means that all headers are requested.
1727 bool bIncludeIt = ( pCtx->pHeaderNames->size() == 0 );
1729 if ( !bIncludeIt )
1731 // Check whether this header was requested.
1732 std::vector< ::rtl::OUString >::const_iterator it(
1733 pCtx->pHeaderNames->begin() );
1734 const std::vector< ::rtl::OUString >::const_iterator end(
1735 pCtx->pHeaderNames->end() );
1737 while ( it != end )
1739 // header names are case insensitive
1740 if ( (*it).equalsIgnoreAsciiCase( aHeaderName ) )
1742 aHeaderName = (*it);
1743 break;
1745 ++it;
1748 if ( it != end )
1749 bIncludeIt = true;
1752 if ( bIncludeIt )
1754 // Create & set the PropertyValue
1755 DAVPropertyValue thePropertyValue;
1756 thePropertyValue.IsCaseSensitive = false;
1757 thePropertyValue.Name = aHeaderName;
1759 if ( nPos < aHeader.getLength() )
1760 thePropertyValue.Value <<= aHeader.copy( nPos + 1 ).trim();
1762 // Add the newly created PropertyValue
1763 pCtx->pResource->properties.push_back( thePropertyValue );
1768 } // namespace
1770 // -------------------------------------------------------------------
1771 // static
1772 int NeonSession::GET( ne_session * sess,
1773 const char * uri,
1774 ne_block_reader reader,
1775 bool getheaders,
1776 void * userdata )
1778 //struct get_context ctx;
1779 ne_request * req = ne_request_create( sess, "GET", uri );
1780 int ret;
1781 void *cursor = NULL;
1782 const char *name, *value;
1784 #if NEON_VERSION < 0x0250
1785 if ( getheaders )
1786 ne_add_response_header_catcher( req, runResponseHeaderHandler, userdata );
1787 #endif
1788 ne_add_response_body_reader( req, ne_accept_2xx, reader, userdata );
1790 ret = ne_request_dispatch( req );
1792 #if NEON_VERSION >= 0x0250
1793 if ( getheaders )
1795 while ((cursor = ne_response_header_iterate(req, cursor, &name, &value))
1796 != NULL)
1798 char buffer[8192];
1800 ne_snprintf(buffer, sizeof buffer, "%s: %s", name, value);
1802 runResponseHeaderHandler(userdata, buffer);
1805 #endif
1806 if ( ret == NE_OK && ne_get_status( req )->klass != 2 )
1807 ret = NE_ERROR;
1809 ne_request_destroy( req );
1810 return ret;
1813 // -------------------------------------------------------------------
1814 // static
1815 int NeonSession::PUT( ne_session * sess,
1816 const char * uri,
1817 const char * buffer,
1818 size_t size)
1820 ne_request * req = ne_request_create( sess, "PUT", uri );
1821 int ret;
1823 ne_lock_using_resource( req, uri, 0 );
1824 ne_lock_using_parent( req, uri );
1826 ne_set_request_body_buffer( req, buffer, size );
1828 ret = ne_request_dispatch( req );
1830 if ( ret == NE_OK && ne_get_status( req )->klass != 2 )
1831 ret = NE_ERROR;
1833 ne_request_destroy( req );
1834 return ret;
1837 // -------------------------------------------------------------------
1838 int NeonSession::POST( ne_session * sess,
1839 const char * uri,
1840 const char * buffer,
1841 ne_block_reader reader,
1842 void * userdata,
1843 const rtl::OUString & rContentType,
1844 const rtl::OUString & rReferer )
1846 ne_request * req = ne_request_create( sess, "POST", uri );
1847 //struct get_context ctx;
1848 int ret;
1850 RequestDataMap * pData = 0;
1852 if ( rContentType.getLength() || rReferer.getLength() )
1854 // Remember contenttype and referer. Data will be added to HTTP request
1855 // header in in 'PreSendRequest' callback.
1856 pData = static_cast< RequestDataMap* >( m_pRequestData );
1857 (*pData)[ req ] = RequestData( rContentType, rReferer );
1860 //ctx.total = -1;
1861 //ctx.fd = fd;
1862 //ctx.error = 0;
1863 //ctx.session = sess;
1865 ///* Read the value of the Content-Length header into ctx.total */
1866 //ne_add_response_header_handler( req, "Content-Length",
1867 // ne_handle_numeric_header, &ctx.total );
1869 ne_add_response_body_reader( req, ne_accept_2xx, reader, userdata );
1871 ne_set_request_body_buffer( req, buffer, strlen( buffer ) );
1873 ret = ne_request_dispatch( req );
1875 //if ( ctx.error )
1876 // ret = NE_ERROR;
1877 //else
1878 if ( ret == NE_OK && ne_get_status( req )->klass != 2 )
1879 ret = NE_ERROR;
1881 ne_request_destroy( req );
1883 if ( pData )
1885 // Remove request data from session's list.
1886 RequestDataMap::iterator it = pData->find( req );
1887 if ( it != pData->end() )
1888 pData->erase( it );
1891 return ret;
1894 // -------------------------------------------------------------------
1895 // static
1896 bool NeonSession::getDataFromInputStream(
1897 const uno::Reference< io::XInputStream > & xStream,
1898 uno::Sequence< sal_Int8 > & rData,
1899 bool bAppendTrailingZeroByte )
1901 if ( xStream.is() )
1903 uno::Reference< io::XSeekable > xSeekable( xStream, uno::UNO_QUERY );
1904 if ( xSeekable.is() )
1908 sal_Int32 nSize
1909 = sal::static_int_cast<sal_Int32>(xSeekable->getLength());
1910 sal_Int32 nRead
1911 = xStream->readBytes( rData, nSize );
1913 if ( nRead == nSize )
1915 if ( bAppendTrailingZeroByte )
1917 rData.realloc( nSize + 1 );
1918 rData[ nSize ] = sal_Int8( 0 );
1920 return true;
1923 catch ( io::NotConnectedException const & )
1925 // readBytes
1927 catch ( io::BufferSizeExceededException const & )
1929 // readBytes
1931 catch ( io::IOException const & )
1933 // getLength, readBytes
1936 else
1940 uno::Sequence< sal_Int8 > aBuffer;
1941 sal_Int32 nPos = 0;
1943 sal_Int32 nRead = xStream->readSomeBytes( aBuffer, 65536 );
1944 while ( nRead > 0 )
1946 if ( rData.getLength() < ( nPos + nRead ) )
1947 rData.realloc( nPos + nRead );
1949 aBuffer.realloc( nRead );
1950 rtl_copyMemory( (void*)( rData.getArray() + nPos ),
1951 (const void*)aBuffer.getConstArray(),
1952 nRead );
1953 nPos += nRead;
1955 aBuffer.realloc( 0 );
1956 nRead = xStream->readSomeBytes( aBuffer, 65536 );
1959 if ( bAppendTrailingZeroByte )
1961 rData.realloc( nPos + 1 );
1962 rData[ nPos ] = sal_Int8( 0 );
1964 return true;
1966 catch ( io::NotConnectedException const & )
1968 // readBytes
1970 catch ( io::BufferSizeExceededException const & )
1972 // readBytes
1974 catch ( io::IOException const & )
1976 // readBytes
1980 return false;
1982 // -------------------------------------------------------------------
1983 //static
1985 NeonSession::Map NeonSession::certMap;
1987 // ---------------------------------------------------------------------
1988 sal_Bool
1989 NeonSession::isDomainMatch( rtl::OUString certHostName)
1991 rtl::OUString hostName = getHostName();
1993 if (hostName.equalsIgnoreAsciiCase( certHostName ))
1994 return sal_True;
1998 if ( 0 == certHostName.indexOf( rtl::OUString::createFromAscii( "*" ) ) && hostName.getLength() >= certHostName.getLength() )
2000 rtl::OUString cmpStr = certHostName.copy( 1 );
2002 if ( hostName.matchIgnoreAsciiCase( cmpStr, hostName.getLength( ) - cmpStr.getLength()) )
2003 return sal_True;
2007 return sal_False;