Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*************************************************************************
3 : *
4 : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : *
6 : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : *
8 : * OpenOffice.org - a multi-platform office productivity suite
9 : *
10 : * This file is part of OpenOffice.org.
11 : *
12 : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : * it under the terms of the GNU Lesser General Public License version 3
14 : * only, as published by the Free Software Foundation.
15 : *
16 : * OpenOffice.org is distributed in the hope that it will be useful,
17 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : * GNU Lesser General Public License version 3 for more details
20 : * (a copy is included in the LICENSE file that accompanied this code).
21 : *
22 : * You should have received a copy of the GNU Lesser General Public License
23 : * version 3 along with OpenOffice.org. If not, see
24 : * <http://www.openoffice.org/license.html>
25 : * for a copy of the LGPLv3 License.
26 : *
27 : ************************************************************************/
28 :
29 :
30 : #include <unordered_map>
31 : #include <vector>
32 : #include <string.h>
33 : #include "osl/diagnose.h"
34 : #include "osl/time.h"
35 : #include <rtl/string.h>
36 : #include <ne_socket.h>
37 : #include <ne_auth.h>
38 : #include <ne_redirect.h>
39 : #include <ne_ssl.h>
40 :
41 : // old neon versions forgot to set this
42 : extern "C" {
43 : #include <ne_compress.h>
44 : }
45 :
46 : #include "libxml/parser.h"
47 : #include "rtl/ustrbuf.hxx"
48 : #include "comphelper/processfactory.hxx"
49 : #include "comphelper/sequence.hxx"
50 : #include <comphelper/stl_types.hxx>
51 : #include "ucbhelper/simplecertificatevalidationrequest.hxx"
52 :
53 : #include "DAVAuthListener.hxx"
54 : #include "NeonTypes.hxx"
55 : #include "NeonSession.hxx"
56 : #include "NeonInputStream.hxx"
57 : #include "NeonPropFindRequest.hxx"
58 : #include "NeonHeadRequest.hxx"
59 : #include "NeonUri.hxx"
60 : #include "LinkSequence.hxx"
61 : #include "UCBDeadPropertyValue.hxx"
62 :
63 : #include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
64 : #include <com/sun/star/security/XCertificate.hpp>
65 : #include <com/sun/star/security/CertificateValidity.hpp>
66 : #include <com/sun/star/security/CertificateContainerStatus.hpp>
67 : #include <com/sun/star/security/CertificateContainer.hpp>
68 : #include <com/sun/star/security/XCertificateContainer.hpp>
69 : #include <com/sun/star/ucb/Lock.hpp>
70 : #include <com/sun/star/beans/NamedValue.hpp>
71 : #include <com/sun/star/xml/crypto/SEInitializer.hpp>
72 :
73 : #include <boost/bind.hpp>
74 :
75 : using namespace com::sun::star;
76 : using namespace webdav_ucp;
77 :
78 : #ifndef EOL
79 : # define EOL "\r\n"
80 : #endif
81 :
82 0 : struct RequestData
83 : {
84 : // POST
85 : OUString aContentType;
86 : OUString aReferer;
87 :
88 0 : RequestData() {}
89 0 : RequestData( const OUString & rContentType,
90 : const OUString & rReferer )
91 0 : : aContentType( rContentType ), aReferer( rReferer ) {}
92 : };
93 :
94 : struct equalPtr
95 : {
96 0 : bool operator()( const ne_request* p1, const ne_request* p2 ) const
97 : {
98 0 : return p1 == p2;
99 : }
100 : };
101 :
102 : struct hashPtr
103 : {
104 0 : size_t operator()( const ne_request* p ) const
105 : {
106 0 : return reinterpret_cast<size_t>(p);
107 : }
108 : };
109 :
110 : typedef std::unordered_map
111 : <
112 : ne_request*,
113 : RequestData,
114 : hashPtr,
115 : equalPtr
116 : >
117 : RequestDataMap;
118 :
119 0 : static sal_uInt16 makeStatusCode( const OUString & rStatusText )
120 : {
121 : // Extract status code from session error string. Unfortunately
122 : // neon provides no direct access to the status code...
123 :
124 0 : if ( rStatusText.getLength() < 3 )
125 : {
126 : OSL_FAIL(
127 : "makeStatusCode - status text string to short!" );
128 0 : return 0;
129 : }
130 :
131 0 : sal_Int32 nPos = rStatusText.indexOf( ' ' );
132 0 : if ( nPos == -1 )
133 : {
134 : OSL_FAIL( "makeStatusCode - wrong status text format!" );
135 0 : return 0;
136 : }
137 :
138 0 : return sal_uInt16( rStatusText.copy( 0, nPos ).toInt32() );
139 : }
140 :
141 0 : static bool noKeepAlive( const uno::Sequence< beans::NamedValue >& rFlags )
142 : {
143 0 : if ( !rFlags.hasElements() )
144 0 : return false;
145 :
146 : // find "KeepAlive" property
147 0 : const beans::NamedValue* pAry(rFlags.getConstArray());
148 0 : const sal_Int32 nLen(rFlags.getLength());
149 : const beans::NamedValue* pValue(
150 : std::find_if(pAry,pAry+nLen,
151 : boost::bind(comphelper::TNamedValueEqualFunctor(),
152 : _1,
153 0 : OUString("KeepAlive"))));
154 0 : if ( pValue != pAry+nLen && !pValue->Value.get<sal_Bool>() )
155 0 : return true;
156 :
157 0 : return false;
158 : }
159 :
160 0 : struct NeonRequestContext
161 : {
162 : uno::Reference< io::XOutputStream > xOutputStream;
163 : rtl::Reference< NeonInputStream > xInputStream;
164 : const std::vector< OUString > * pHeaderNames;
165 : DAVResource * pResource;
166 :
167 0 : explicit NeonRequestContext( uno::Reference< io::XOutputStream > & xOutStrm )
168 : : xOutputStream( xOutStrm ), xInputStream( 0 ),
169 0 : pHeaderNames( 0 ), pResource( 0 ) {}
170 :
171 0 : explicit NeonRequestContext( const rtl::Reference< NeonInputStream > & xInStrm )
172 : : xOutputStream( 0 ), xInputStream( xInStrm ),
173 0 : pHeaderNames( 0 ), pResource( 0 ) {}
174 :
175 0 : NeonRequestContext( uno::Reference< io::XOutputStream > & xOutStrm,
176 : const std::vector< OUString > & inHeaderNames,
177 : DAVResource & ioResource )
178 : : xOutputStream( xOutStrm ), xInputStream( 0 ),
179 0 : pHeaderNames( &inHeaderNames ), pResource( &ioResource ) {}
180 :
181 0 : NeonRequestContext( const rtl::Reference< NeonInputStream > & xInStrm,
182 : const std::vector< OUString > & inHeaderNames,
183 : DAVResource & ioResource )
184 : : xOutputStream( 0 ), xInputStream( xInStrm ),
185 0 : pHeaderNames( &inHeaderNames ), pResource( &ioResource ) {}
186 : };
187 :
188 : // A simple Neon response_block_reader for use with an XInputStream
189 0 : extern "C" int NeonSession_ResponseBlockReader(void * inUserData,
190 : const char * inBuf,
191 : size_t inLen )
192 : {
193 : // neon sometimes calls this function with (inLen == 0)...
194 0 : if ( inLen > 0 )
195 : {
196 : NeonRequestContext * pCtx
197 0 : = static_cast< NeonRequestContext * >( inUserData );
198 :
199 : rtl::Reference< NeonInputStream > xInputStream(
200 0 : pCtx->xInputStream );
201 :
202 0 : if ( xInputStream.is() )
203 0 : xInputStream->AddToStream( inBuf, inLen );
204 : }
205 0 : return 0;
206 : }
207 :
208 : // A simple Neon response_block_reader for use with an XOutputStream
209 0 : extern "C" int NeonSession_ResponseBlockWriter( void * inUserData,
210 : const char * inBuf,
211 : size_t inLen )
212 : {
213 : // neon calls this function with (inLen == 0)...
214 0 : if ( inLen > 0 )
215 : {
216 : NeonRequestContext * pCtx
217 0 : = static_cast< NeonRequestContext * >( inUserData );
218 : uno::Reference< io::XOutputStream > xOutputStream
219 0 : = pCtx->xOutputStream;
220 :
221 0 : if ( xOutputStream.is() )
222 : {
223 0 : const uno::Sequence< sal_Int8 > aSeq( reinterpret_cast<sal_Int8 const *>(inBuf), inLen );
224 0 : xOutputStream->writeBytes( aSeq );
225 0 : }
226 : }
227 0 : return 0;
228 : }
229 :
230 0 : extern "C" int NeonSession_NeonAuth( void * inUserData,
231 : #if defined NE_FEATURE_SSPI && ! defined SYSTEM_NEON
232 : const char * inAuthProtocol,
233 : #endif
234 : const char * inRealm,
235 : int attempt,
236 : char * inoutUserName,
237 : char * inoutPassWord )
238 : {
239 : /* The callback used to request the username and password in the given
240 : * realm. The username and password must be copied into the buffers
241 : * which are both of size NE_ABUFSIZ. The 'attempt' parameter is zero
242 : * on the first call to the callback, and increases by one each time
243 : * an attempt to authenticate fails.
244 : *
245 : * The callback must return zero to indicate that authentication
246 : * should be attempted with the username/password, or non-zero to
247 : * cancel the request. (if non-zero, username and password are
248 : * ignored.) */
249 :
250 0 : NeonSession * theSession = static_cast< NeonSession * >( inUserData );
251 : DAVAuthListener * pListener
252 0 : = theSession->getRequestEnvironment().m_xAuthListener.get();
253 0 : if ( !pListener )
254 : {
255 : // abort
256 0 : return -1;
257 : }
258 0 : OUString theUserName;
259 0 : OUString thePassWord;
260 :
261 0 : if ( attempt == 0 )
262 : {
263 : // neon does not handle username supplied with request URI (for
264 : // instance when doing FTP over proxy - last checked: 0.23.5 )
265 :
266 : try
267 : {
268 0 : NeonUri uri( theSession->getRequestEnvironment().m_aRequestURI );
269 0 : OUString aUserInfo( uri.GetUserInfo() );
270 0 : if ( !aUserInfo.isEmpty() )
271 : {
272 0 : sal_Int32 nPos = aUserInfo.indexOf( '@' );
273 0 : if ( nPos == -1 )
274 : {
275 0 : theUserName = aUserInfo;
276 : }
277 : else
278 : {
279 0 : theUserName = aUserInfo.copy( 0, nPos );
280 0 : thePassWord = aUserInfo.copy( nPos + 1 );
281 : }
282 0 : }
283 : }
284 0 : catch ( DAVException const & )
285 : {
286 : // abort
287 0 : return -1;
288 : }
289 : }
290 : else
291 : {
292 : // username buffer is prefilled with user name from last attempt.
293 0 : theUserName = OUString::createFromAscii( inoutUserName );
294 : // @@@ Neon does not initialize password buffer (last checked: 0.22.0).
295 : //thePassWord = OUString::createFromAscii( inoutPassWord );
296 : }
297 :
298 0 : bool bCanUseSystemCreds = false;
299 :
300 : #if defined NE_FEATURE_SSPI && ! defined SYSTEM_NEON
301 : bCanUseSystemCreds
302 : = (attempt == 0) && // avoid endless loops
303 : ne_has_support( NE_FEATURE_SSPI ) && // Windows-only feature.
304 : ( ( ne_strcasecmp( inAuthProtocol, "NTLM" ) == 0 ) ||
305 : ( ne_strcasecmp( inAuthProtocol, "Negotiate" ) == 0 ) );
306 : #endif
307 :
308 : int theRetVal = pListener->authenticate(
309 : OUString::createFromAscii( inRealm ),
310 0 : theSession->getHostName(),
311 : theUserName,
312 : thePassWord,
313 0 : bCanUseSystemCreds);
314 :
315 : OString aUser(
316 0 : OUStringToOString( theUserName, RTL_TEXTENCODING_UTF8 ) );
317 0 : if ( aUser.getLength() > ( NE_ABUFSIZ - 1 ) )
318 : {
319 : OSL_FAIL(
320 : "NeonSession_NeonAuth - username to long!" );
321 0 : return -1;
322 : }
323 :
324 : OString aPass(
325 0 : OUStringToOString( thePassWord, RTL_TEXTENCODING_UTF8 ) );
326 0 : if ( aPass.getLength() > ( NE_ABUFSIZ - 1 ) )
327 : {
328 : OSL_FAIL(
329 : "NeonSession_NeonAuth - password to long!" );
330 0 : return -1;
331 : }
332 :
333 : strcpy( inoutUserName, // #100211# - checked
334 0 : OUStringToOString( theUserName, RTL_TEXTENCODING_UTF8 ).getStr() );
335 :
336 : strcpy( inoutPassWord, // #100211# - checked
337 0 : OUStringToOString( thePassWord, RTL_TEXTENCODING_UTF8 ).getStr() );
338 :
339 0 : return theRetVal;
340 : }
341 :
342 : namespace {
343 0 : OUString GetHostnamePart( const OUString& _rRawString )
344 : {
345 0 : OUString sPart;
346 0 : OUString sPartId("CN=");
347 0 : sal_Int32 nContStart = _rRawString.indexOf( sPartId );
348 0 : if ( nContStart != -1 )
349 : {
350 0 : nContStart += sPartId.getLength();
351 0 : sal_Int32 nContEnd = _rRawString.indexOf( ',', nContStart );
352 0 : sPart = _rRawString.copy( nContStart, nContEnd - nContStart );
353 : }
354 0 : return sPart;
355 : }
356 : } // namespace
357 :
358 0 : extern "C" int NeonSession_CertificationNotify( void *userdata,
359 : int failures,
360 : const ne_ssl_certificate *cert )
361 : {
362 : OSL_ASSERT( cert );
363 :
364 0 : NeonSession * pSession = static_cast< NeonSession * >( userdata );
365 0 : uno::Reference< security::XCertificateContainer > xCertificateContainer;
366 : try
367 : {
368 0 : xCertificateContainer = security::CertificateContainer::create( pSession->getComponentContext() );
369 : }
370 0 : catch ( uno::Exception const & )
371 : {
372 : }
373 :
374 0 : if ( !xCertificateContainer.is() )
375 0 : return 1;
376 :
377 0 : failures = 0;
378 :
379 0 : char * dn = ne_ssl_readable_dname( ne_ssl_cert_subject( cert ) );
380 0 : OUString cert_subject( dn, strlen( dn ), RTL_TEXTENCODING_UTF8, 0 );
381 :
382 0 : ne_free( dn );
383 :
384 : security::CertificateContainerStatus certificateContainer(
385 0 : xCertificateContainer->hasCertificate(
386 0 : pSession->getHostName(), cert_subject ) );
387 :
388 0 : if ( certificateContainer != security::CertificateContainerStatus_NOCERT )
389 : return
390 : certificateContainer == security::CertificateContainerStatus_TRUSTED
391 : ? 0
392 0 : : 1;
393 :
394 0 : uno::Reference< xml::crypto::XSEInitializer > xSEInitializer;
395 : try
396 : {
397 0 : xSEInitializer = xml::crypto::SEInitializer::create( pSession->getComponentContext() );
398 : }
399 0 : catch ( uno::Exception const & )
400 : {
401 : }
402 :
403 0 : if ( !xSEInitializer.is() )
404 0 : return 1;
405 :
406 : uno::Reference< xml::crypto::XXMLSecurityContext > xSecurityContext(
407 0 : xSEInitializer->createSecurityContext( OUString() ) );
408 :
409 : uno::Reference< xml::crypto::XSecurityEnvironment > xSecurityEnv(
410 0 : xSecurityContext->getSecurityEnvironment() );
411 :
412 : //The end entity certificate
413 0 : char * eeCertB64 = ne_ssl_cert_export( cert );
414 :
415 0 : OString sEECertB64( eeCertB64 );
416 :
417 : uno::Reference< security::XCertificate > xEECert(
418 0 : xSecurityEnv->createCertificateFromAscii(
419 0 : OStringToOUString( sEECertB64, RTL_TEXTENCODING_ASCII_US ) ) );
420 :
421 0 : ne_free( eeCertB64 );
422 0 : eeCertB64 = 0;
423 :
424 0 : std::vector< uno::Reference< security::XCertificate > > vecCerts;
425 0 : const ne_ssl_certificate * issuerCert = cert;
426 : do
427 : {
428 : //get the intermediate certificate
429 : //the returned value is const ! Therfore it does not need to be freed
430 : //with ne_ssl_cert_free, which takes a non-const argument
431 0 : issuerCert = ne_ssl_cert_signedby( issuerCert );
432 0 : if ( NULL == issuerCert )
433 0 : break;
434 :
435 0 : char * imCertB64 = ne_ssl_cert_export( issuerCert );
436 0 : OString sInterMediateCertB64( imCertB64 );
437 0 : ne_free( imCertB64 );
438 :
439 : uno::Reference< security::XCertificate> xImCert(
440 0 : xSecurityEnv->createCertificateFromAscii(
441 0 : OStringToOUString( sInterMediateCertB64, RTL_TEXTENCODING_ASCII_US ) ) );
442 0 : if ( xImCert.is() )
443 0 : vecCerts.push_back( xImCert );
444 : }
445 : while ( true );
446 :
447 0 : sal_Int64 certValidity = xSecurityEnv->verifyCertificate( xEECert,
448 0 : ::comphelper::containerToSequence( vecCerts ) );
449 :
450 0 : if ( pSession->isDomainMatch(
451 0 : GetHostnamePart( xEECert.get()->getSubjectName() ) ) )
452 : {
453 : // if host name matched with certificate then look if the
454 : // certificate was ok
455 0 : if( certValidity == security::CertificateValidity::VALID )
456 0 : return 0;
457 : }
458 :
459 : const uno::Reference< ucb::XCommandEnvironment > xEnv(
460 0 : pSession->getRequestEnvironment().m_xEnv );
461 0 : if ( xEnv.is() )
462 : {
463 0 : failures = static_cast< int >( certValidity );
464 :
465 : uno::Reference< task::XInteractionHandler > xIH(
466 0 : xEnv->getInteractionHandler() );
467 0 : if ( xIH.is() )
468 : {
469 : rtl::Reference< ucbhelper::SimpleCertificateValidationRequest >
470 : xRequest( new ucbhelper::SimpleCertificateValidationRequest(
471 0 : (sal_Int32)failures, xEECert, pSession->getHostName() ) );
472 0 : xIH->handle( xRequest.get() );
473 :
474 : rtl::Reference< ucbhelper::InteractionContinuation > xSelection
475 0 : = xRequest->getSelection();
476 :
477 0 : if ( xSelection.is() )
478 : {
479 : uno::Reference< task::XInteractionApprove > xApprove(
480 0 : xSelection.get(), uno::UNO_QUERY );
481 0 : if ( xApprove.is() )
482 : {
483 0 : xCertificateContainer->addCertificate(
484 0 : pSession->getHostName(), cert_subject, sal_True );
485 0 : return 0;
486 : }
487 : else
488 : {
489 : // Don't trust cert
490 0 : xCertificateContainer->addCertificate(
491 0 : pSession->getHostName(), cert_subject, sal_False );
492 0 : return 1;
493 0 : }
494 0 : }
495 : }
496 : else
497 : {
498 : // Don't trust cert
499 0 : xCertificateContainer->addCertificate(
500 0 : pSession->getHostName(), cert_subject, sal_False );
501 0 : return 1;
502 0 : }
503 : }
504 0 : return 1;
505 : }
506 :
507 0 : extern "C" void NeonSession_PreSendRequest( ne_request * req,
508 : void * userdata,
509 : ne_buffer * headers )
510 : {
511 : // userdata -> value returned by 'create'
512 :
513 0 : NeonSession * pSession = static_cast< NeonSession * >( userdata );
514 0 : if ( pSession )
515 : {
516 : // If there is a proxy server in between, it shall never use
517 : // cached data. We always want 'up-to-date' data.
518 0 : ne_buffer_concat( headers, "Pragma: no-cache", EOL, NULL );
519 : // alternative, but understoud by HTTP 1.1 servers only:
520 : // ne_buffer_concat( headers, "Cache-Control: max-age=0", EOL, NULL );
521 :
522 : const RequestDataMap * pRequestData
523 : = static_cast< const RequestDataMap* >(
524 0 : pSession->getRequestData() );
525 :
526 0 : RequestDataMap::const_iterator it = pRequestData->find( req );
527 0 : if ( it != pRequestData->end() )
528 : {
529 0 : if ( !(*it).second.aContentType.isEmpty() )
530 : {
531 0 : char * pData = headers->data;
532 0 : if ( strstr( pData, "Content-Type:" ) == NULL )
533 : {
534 : OString aType
535 0 : = OUStringToOString( (*it).second.aContentType,
536 0 : RTL_TEXTENCODING_UTF8 );
537 : ne_buffer_concat( headers, "Content-Type: ",
538 0 : aType.getStr(), EOL, NULL );
539 : }
540 : }
541 :
542 0 : if ( !(*it).second.aReferer.isEmpty() )
543 : {
544 0 : char * pData = headers->data;
545 0 : if ( strstr( pData, "Referer:" ) == NULL )
546 : {
547 : OString aReferer
548 0 : = OUStringToOString( (*it).second.aReferer,
549 0 : RTL_TEXTENCODING_UTF8 );
550 : ne_buffer_concat( headers, "Referer: ",
551 0 : aReferer.getStr(), EOL, NULL );
552 : }
553 : }
554 : }
555 :
556 : const DAVRequestHeaders & rHeaders
557 0 : = pSession->getRequestEnvironment().m_aRequestHeaders;
558 :
559 0 : DAVRequestHeaders::const_iterator it1( rHeaders.begin() );
560 0 : const DAVRequestHeaders::const_iterator end1( rHeaders.end() );
561 :
562 0 : while ( it1 != end1 )
563 : {
564 : OString aHeader
565 0 : = OUStringToOString( (*it1).first,
566 0 : RTL_TEXTENCODING_UTF8 );
567 : OString aValue
568 0 : = OUStringToOString( (*it1).second,
569 0 : RTL_TEXTENCODING_UTF8 );
570 : ne_buffer_concat( headers, aHeader.getStr(), ": ",
571 0 : aValue.getStr(), EOL, NULL );
572 :
573 0 : ++it1;
574 0 : }
575 : }
576 0 : }
577 :
578 : // static members
579 : bool NeonSession::m_bGlobalsInited = false;
580 : //See https://bugzilla.redhat.com/show_bug.cgi?id=544619#c4
581 : //neon is threadsafe, but uses gnutls which is only thread-safe
582 : //if initialized to be thread-safe. cups, unfortunately, generally
583 : //initializes it first, and as non-thread-safe, leaving the entire
584 : //stack unsafe
585 2 : osl::Mutex aGlobalNeonMutex;
586 2 : NeonLockStore NeonSession::m_aNeonLockStore;
587 :
588 0 : NeonSession::NeonSession( const rtl::Reference< DAVSessionFactory > & rSessionFactory,
589 : const OUString& inUri,
590 : const uno::Sequence< beans::NamedValue >& rFlags,
591 : const ucbhelper::InternetProxyDecider & rProxyDecider )
592 : throw ( std::exception )
593 : : DAVSession( rSessionFactory )
594 : , m_nProxyPort( 0 )
595 : , m_aFlags( rFlags )
596 : , m_pHttpSession( 0 )
597 0 : , m_pRequestData( new RequestDataMap )
598 0 : , m_rProxyDecider( rProxyDecider )
599 : {
600 0 : NeonUri theUri( inUri );
601 0 : m_aScheme = theUri.GetScheme();
602 0 : m_aHostName = theUri.GetHost();
603 0 : m_nPort = theUri.GetPort();
604 0 : }
605 :
606 0 : NeonSession::~NeonSession( )
607 : {
608 0 : if ( m_pHttpSession )
609 : {
610 : {
611 0 : osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex );
612 0 : ne_session_destroy( m_pHttpSession );
613 : }
614 0 : m_pHttpSession = 0;
615 : }
616 0 : delete static_cast< RequestDataMap * >( m_pRequestData );
617 0 : }
618 :
619 0 : void NeonSession::Init( const DAVRequestEnvironment & rEnv )
620 : throw (css::uno::RuntimeException, std::exception)
621 : {
622 0 : osl::Guard< osl::Mutex > theGuard( m_aMutex );
623 0 : m_aEnv = rEnv;
624 0 : Init();
625 0 : }
626 :
627 0 : void NeonSession::Init()
628 : throw (css::uno::RuntimeException, std::exception)
629 : {
630 0 : osl::Guard< osl::Mutex > theGuard( m_aMutex );
631 :
632 0 : bool bCreateNewSession = false;
633 :
634 0 : if ( m_pHttpSession == 0 )
635 : {
636 : // Ensure that Neon sockets are initialized
637 0 : osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex );
638 0 : if ( !m_bGlobalsInited )
639 : {
640 0 : if ( ne_sock_init() != 0 )
641 : throw DAVException( DAVException::DAV_SESSION_CREATE,
642 : NeonUri::makeConnectionEndPointString(
643 0 : m_aHostName, m_nPort ) );
644 :
645 : // #122205# - libxml2 needs to be initialized once if used by
646 : // multithreaded programs like OOo.
647 0 : xmlInitParser();
648 : #if OSL_DEBUG_LEVEL > 0
649 : // for more debug flags see ne_utils.h; NE_DEBUGGING must be defined
650 : // while compiling neon in order to actually activate neon debug
651 : // output.
652 : ne_debug_init( stderr, NE_DBG_FLUSH
653 : | NE_DBG_HTTP
654 : // | NE_DBG_HTTPBODY
655 : // | NE_DBG_HTTPAUTH
656 : // | NE_DBG_XML
657 : // | NE_DBG_XMLPARSE
658 : | NE_DBG_LOCKS
659 : | NE_DBG_SSL
660 : );
661 : #endif
662 0 : m_bGlobalsInited = true;
663 : }
664 :
665 0 : const ucbhelper::InternetProxyServer & rProxyCfg = getProxySettings();
666 :
667 0 : m_aProxyName = rProxyCfg.aName;
668 0 : m_nProxyPort = rProxyCfg.nPort;
669 :
670 : // Not yet initialized. Create new session.
671 0 : bCreateNewSession = true;
672 : }
673 : else
674 : {
675 : // #112271# Check whether proxy settings are still valid (They may
676 : // change at any time). If not, create new Neon session.
677 :
678 0 : const ucbhelper::InternetProxyServer & rProxyCfg = getProxySettings();
679 :
680 0 : if ( ( rProxyCfg.aName != m_aProxyName )
681 0 : || ( rProxyCfg.nPort != m_nProxyPort ) )
682 : {
683 0 : m_aProxyName = rProxyCfg.aName;
684 0 : m_nProxyPort = rProxyCfg.nPort;
685 :
686 : // new session needed, destroy old first
687 : {
688 0 : osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex );
689 0 : ne_session_destroy( m_pHttpSession );
690 : }
691 0 : m_pHttpSession = 0;
692 0 : bCreateNewSession = true;
693 : }
694 : }
695 :
696 0 : if ( bCreateNewSession )
697 : {
698 : // @@@ For FTP over HTTP proxy inUserInfo is needed to be able to
699 : // build the complete request URI (including user:pass), but
700 : // currently (0.22.0) neon does not allow to pass the user info
701 : // to the session
702 :
703 : {
704 0 : osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex );
705 : m_pHttpSession = ne_session_create(
706 : OUStringToOString( m_aScheme, RTL_TEXTENCODING_UTF8 ).getStr(),
707 : /* theUri.GetUserInfo(),
708 : @@@ for FTP via HTTP proxy, but not supported by Neon */
709 : OUStringToOString( m_aHostName, RTL_TEXTENCODING_UTF8 ).getStr(),
710 0 : m_nPort );
711 : }
712 :
713 0 : if ( m_pHttpSession == 0 )
714 : throw DAVException( DAVException::DAV_SESSION_CREATE,
715 : NeonUri::makeConnectionEndPointString(
716 0 : m_aHostName, m_nPort ) );
717 :
718 : // Register the session with the lock store
719 0 : m_aNeonLockStore.registerSession( m_pHttpSession );
720 :
721 0 : if ( m_aScheme.equalsIgnoreAsciiCase(
722 0 : OUString( "https" ) ) )
723 : {
724 : // Set a failure callback for certificate check
725 : ne_ssl_set_verify(
726 0 : m_pHttpSession, NeonSession_CertificationNotify, this);
727 :
728 : // Tell Neon to tell the SSL library used (OpenSSL or
729 : // GnuTLS, I guess) to use a default set of root
730 : // certificates.
731 0 : ne_ssl_trust_default_ca(m_pHttpSession);
732 : }
733 :
734 : // Add hooks (i.e. for adding additional headers to the request)
735 :
736 : #if 0
737 : /* Hook called when a request is created. */
738 : //typedef void (*ne_create_request_fn)(ne_request *req, void *userdata,
739 : // const char *method, const char *path);
740 :
741 : ne_hook_create_request( m_pHttpSession, create_req_hook_fn, this );
742 : #endif
743 :
744 : /* Hook called before the request is sent. 'header' is the raw HTTP
745 : * header before the trailing CRLF is added: add in more here. */
746 : //typedef void (*ne_pre_send_fn)(ne_request *req, void *userdata,
747 : // ne_buffer *header);
748 :
749 0 : ne_hook_pre_send( m_pHttpSession, NeonSession_PreSendRequest, this );
750 : #if 0
751 : /* Hook called after the request is sent. May return:
752 : * NE_OK everything is okay
753 : * NE_RETRY try sending the request again.
754 : * anything else signifies an error, and the request is failed. The
755 : * return code is passed back the _dispatch caller, so the session error
756 : * must also be set appropriately (ne_set_error).
757 : */
758 : //typedef int (*ne_post_send_fn)(ne_request *req, void *userdata,
759 : // const ne_status *status);
760 :
761 : ne_hook_post_send( m_pHttpSession, post_send_req_hook_fn, this );
762 :
763 : /* Hook called when the request is destroyed. */
764 : //typedef void (*ne_destroy_req_fn)(ne_request *req, void *userdata);
765 :
766 : ne_hook_destroy_request( m_pHttpSession, destroy_req_hook_fn, this );
767 :
768 : /* Hook called when the session is destroyed. */
769 : //typedef void (*ne_destroy_sess_fn)(void *userdata);
770 :
771 : ne_hook_destroy_session( m_pHttpSession, destroy_sess_hook_fn, this );
772 : #endif
773 :
774 0 : if ( !m_aProxyName.isEmpty() )
775 : {
776 : ne_session_proxy( m_pHttpSession,
777 : OUStringToOString(
778 : m_aProxyName,
779 : RTL_TEXTENCODING_UTF8 ).getStr(),
780 0 : m_nProxyPort );
781 : }
782 :
783 : // avoid KeepAlive?
784 0 : if ( noKeepAlive(m_aFlags) )
785 0 : ne_set_session_flag( m_pHttpSession, NE_SESSFLAG_PERSIST, 0 );
786 :
787 : // Register for redirects.
788 0 : ne_redirect_register( m_pHttpSession );
789 :
790 : // authentication callbacks.
791 : #if 1
792 0 : ne_add_server_auth( m_pHttpSession, NE_AUTH_ALL, NeonSession_NeonAuth, this );
793 0 : ne_add_proxy_auth ( m_pHttpSession, NE_AUTH_ALL, NeonSession_NeonAuth, this );
794 : #else
795 : ne_set_server_auth( m_pHttpSession, NeonSession_NeonAuth, this );
796 : ne_set_proxy_auth ( m_pHttpSession, NeonSession_NeonAuth, this );
797 : #endif
798 0 : }
799 0 : }
800 :
801 0 : bool NeonSession::CanUse( const OUString & inUri,
802 : const uno::Sequence< beans::NamedValue >& rFlags )
803 : {
804 : try
805 : {
806 0 : NeonUri theUri( inUri );
807 0 : if ( ( theUri.GetPort() == m_nPort ) &&
808 0 : ( theUri.GetHost() == m_aHostName ) &&
809 0 : ( theUri.GetScheme() == m_aScheme ) &&
810 0 : ( rFlags == m_aFlags ) )
811 0 : return true;
812 : }
813 0 : catch ( DAVException const & )
814 : {
815 0 : return false;
816 : }
817 0 : return false;
818 : }
819 :
820 0 : bool NeonSession::UsesProxy()
821 : {
822 0 : Init();
823 0 : return !m_aProxyName.isEmpty() ;
824 : }
825 :
826 0 : void NeonSession::OPTIONS( const OUString & inPath,
827 : DAVCapabilities & outCapabilities,
828 : const DAVRequestEnvironment & rEnv )
829 : throw( std::exception )
830 : {
831 0 : osl::Guard< osl::Mutex > theGuard( m_aMutex );
832 :
833 0 : Init( rEnv );
834 :
835 : HttpServerCapabilities servercaps;
836 0 : memset( &servercaps, 0, sizeof( servercaps ) );
837 :
838 : int theRetVal = ne_options( m_pHttpSession,
839 : OUStringToOString(
840 : inPath, RTL_TEXTENCODING_UTF8 ).getStr(),
841 0 : &servercaps );
842 :
843 0 : HandleError( theRetVal, inPath, rEnv );
844 :
845 0 : outCapabilities.class1 = !!servercaps.dav_class1;
846 0 : outCapabilities.class2 = !!servercaps.dav_class2;
847 0 : outCapabilities.executable = !!servercaps.dav_executable;
848 0 : }
849 :
850 0 : void NeonSession::PROPFIND( const OUString & inPath,
851 : const Depth inDepth,
852 : const std::vector< OUString > & inPropNames,
853 : std::vector< DAVResource > & ioResources,
854 : const DAVRequestEnvironment & rEnv )
855 : throw ( std::exception )
856 : {
857 0 : osl::Guard< osl::Mutex > theGuard( m_aMutex );
858 :
859 0 : Init( rEnv );
860 :
861 0 : int theRetVal = NE_OK;
862 : NeonPropFindRequest theRequest( m_pHttpSession,
863 : OUStringToOString(
864 : inPath, RTL_TEXTENCODING_UTF8 ).getStr(),
865 : inDepth,
866 : inPropNames,
867 : ioResources,
868 0 : theRetVal );
869 :
870 0 : HandleError( theRetVal, inPath, rEnv );
871 0 : }
872 :
873 0 : void NeonSession::PROPFIND( const OUString & inPath,
874 : const Depth inDepth,
875 : std::vector< DAVResourceInfo > & ioResInfo,
876 : const DAVRequestEnvironment & rEnv )
877 : throw( std::exception )
878 : {
879 0 : osl::Guard< osl::Mutex > theGuard( m_aMutex );
880 :
881 0 : Init( rEnv );
882 :
883 0 : int theRetVal = NE_OK;
884 : NeonPropFindRequest theRequest( m_pHttpSession,
885 : OUStringToOString(
886 : inPath, RTL_TEXTENCODING_UTF8 ).getStr(),
887 : inDepth,
888 : ioResInfo,
889 0 : theRetVal );
890 :
891 0 : HandleError( theRetVal, inPath, rEnv );
892 0 : }
893 :
894 0 : void NeonSession::PROPPATCH( const OUString & inPath,
895 : const std::vector< ProppatchValue > & inValues,
896 : const DAVRequestEnvironment & rEnv )
897 : throw( std::exception )
898 : {
899 : /* @@@ Which standard live properties can be set by the client?
900 : This is a known WebDAV RFC issue ( verified: 04/10/2001 )
901 : --> http://www.ics.uci.edu/pub/ietf/webdav/protocol/issues.html
902 :
903 : mod_dav implementation:
904 :
905 : creationdate r ( File System prop )
906 : displayname w
907 : getcontentlanguage r ( #ifdef DAV_DISABLE_WRITEABLE_PROPS )
908 : getcontentlength r ( File System prop )
909 : getcontenttype r ( #ifdef DAV_DISABLE_WRITEABLE_PROPS )
910 : getetag r ( File System prop )
911 : getlastmodified r ( File System prop )
912 : lockdiscovery r
913 : resourcetype r
914 : source w
915 : supportedlock r
916 : executable w ( #ifndef WIN32 )
917 :
918 : All dead properties are of course writable.
919 : */
920 :
921 0 : int theRetVal = NE_OK;
922 :
923 : int n; // for the "for" loop
924 :
925 : // Generate the list of properties we want to set.
926 0 : int nPropCount = inValues.size();
927 : ne_proppatch_operation* pItems
928 0 : = new ne_proppatch_operation[ nPropCount + 1 ];
929 0 : for ( n = 0; n < nPropCount; ++n )
930 : {
931 0 : const ProppatchValue & rValue = inValues[ n ];
932 :
933 : // Split fullname into namespace and name!
934 0 : ne_propname * pName = new ne_propname;
935 0 : DAVProperties::createNeonPropName( rValue.name, *pName );
936 0 : pItems[ n ].name = pName;
937 :
938 0 : if ( rValue.operation == PROPSET )
939 : {
940 0 : pItems[ n ].type = ne_propset;
941 :
942 0 : OUString aStringValue;
943 0 : if ( DAVProperties::isUCBDeadProperty( *pName ) )
944 : {
945 : // DAV dead property added by WebDAV UCP?
946 0 : if ( !UCBDeadPropertyValue::toXML( rValue.value,
947 0 : aStringValue ) )
948 : {
949 : // Error!
950 0 : pItems[ n ].value = 0;
951 0 : theRetVal = NE_ERROR;
952 0 : nPropCount = n + 1;
953 0 : break;
954 : }
955 : }
956 0 : else if ( !( rValue.value >>= aStringValue ) )
957 : {
958 : // complex properties...
959 0 : if ( rValue.name == DAVProperties::SOURCE )
960 : {
961 0 : uno::Sequence< ucb::Link > aLinks;
962 0 : if ( rValue.value >>= aLinks )
963 : {
964 0 : LinkSequence::toXML( aLinks, aStringValue );
965 : }
966 : else
967 : {
968 : // Error!
969 0 : pItems[ n ].value = 0;
970 0 : theRetVal = NE_ERROR;
971 0 : nPropCount = n + 1;
972 0 : break;
973 0 : }
974 : }
975 : else
976 : {
977 : OSL_FAIL( "NeonSession::PROPPATCH - unsupported type!" );
978 : // Error!
979 0 : pItems[ n ].value = 0;
980 0 : theRetVal = NE_ERROR;
981 0 : nPropCount = n + 1;
982 0 : break;
983 : }
984 : }
985 0 : pItems[ n ].value
986 : = strdup( OUStringToOString( aStringValue,
987 0 : RTL_TEXTENCODING_UTF8 ).getStr() );
988 : }
989 : else
990 : {
991 0 : pItems[ n ].type = ne_propremove;
992 0 : pItems[ n ].value = 0;
993 : }
994 : }
995 :
996 0 : if ( theRetVal == NE_OK )
997 : {
998 0 : osl::Guard< osl::Mutex > theGuard( m_aMutex );
999 :
1000 0 : Init( rEnv );
1001 :
1002 0 : pItems[ n ].name = 0;
1003 :
1004 : theRetVal = ne_proppatch( m_pHttpSession,
1005 : OUStringToOString(
1006 : inPath, RTL_TEXTENCODING_UTF8 ).getStr(),
1007 0 : pItems );
1008 : }
1009 :
1010 0 : for ( n = 0; n < nPropCount; ++n )
1011 : {
1012 0 : free( const_cast<char *>(pItems[ n ].name->name) );
1013 0 : delete pItems[ n ].name;
1014 0 : free( const_cast<char *>(pItems[ n ].value) );
1015 : }
1016 :
1017 0 : delete [] pItems;
1018 :
1019 0 : HandleError( theRetVal, inPath, rEnv );
1020 0 : }
1021 :
1022 0 : void NeonSession::HEAD( const OUString & inPath,
1023 : const std::vector< OUString > & inHeaderNames,
1024 : DAVResource & ioResource,
1025 : const DAVRequestEnvironment & rEnv )
1026 : throw( std::exception )
1027 : {
1028 0 : osl::Guard< osl::Mutex > theGuard( m_aMutex );
1029 :
1030 0 : Init( rEnv );
1031 :
1032 0 : int theRetVal = NE_OK;
1033 : NeonHeadRequest theRequest( m_pHttpSession,
1034 : inPath,
1035 : inHeaderNames,
1036 : ioResource,
1037 0 : theRetVal );
1038 :
1039 0 : HandleError( theRetVal, inPath, rEnv );
1040 0 : }
1041 :
1042 : uno::Reference< io::XInputStream >
1043 0 : NeonSession::GET( const OUString & inPath,
1044 : const DAVRequestEnvironment & rEnv )
1045 : throw ( std::exception )
1046 : {
1047 0 : osl::Guard< osl::Mutex > theGuard( m_aMutex );
1048 :
1049 0 : Init( rEnv );
1050 :
1051 0 : rtl::Reference< NeonInputStream > xInputStream( new NeonInputStream );
1052 0 : NeonRequestContext aCtx( xInputStream );
1053 : int theRetVal = GET( m_pHttpSession,
1054 : OUStringToOString(
1055 : inPath, RTL_TEXTENCODING_UTF8 ).getStr(),
1056 : NeonSession_ResponseBlockReader,
1057 : false,
1058 0 : &aCtx );
1059 :
1060 0 : HandleError( theRetVal, inPath, rEnv );
1061 :
1062 0 : return uno::Reference< io::XInputStream >( xInputStream.get() );
1063 : }
1064 :
1065 0 : void NeonSession::GET( const OUString & inPath,
1066 : uno::Reference< io::XOutputStream > & ioOutputStream,
1067 : const DAVRequestEnvironment & rEnv )
1068 : throw ( std::exception )
1069 : {
1070 0 : osl::Guard< osl::Mutex > theGuard( m_aMutex );
1071 :
1072 0 : Init( rEnv );
1073 :
1074 0 : NeonRequestContext aCtx( ioOutputStream );
1075 : int theRetVal = GET( m_pHttpSession,
1076 : OUStringToOString(
1077 : inPath, RTL_TEXTENCODING_UTF8 ).getStr(),
1078 : NeonSession_ResponseBlockWriter,
1079 : false,
1080 0 : &aCtx );
1081 :
1082 0 : HandleError( theRetVal, inPath, rEnv );
1083 0 : }
1084 :
1085 : uno::Reference< io::XInputStream >
1086 0 : NeonSession::GET( const OUString & inPath,
1087 : const std::vector< OUString > & inHeaderNames,
1088 : DAVResource & ioResource,
1089 : const DAVRequestEnvironment & rEnv )
1090 : throw ( std::exception )
1091 : {
1092 0 : osl::Guard< osl::Mutex > theGuard( m_aMutex );
1093 :
1094 0 : Init( rEnv );
1095 :
1096 0 : ioResource.uri = inPath;
1097 0 : ioResource.properties.clear();
1098 :
1099 0 : rtl::Reference< NeonInputStream > xInputStream( new NeonInputStream );
1100 0 : NeonRequestContext aCtx( xInputStream, inHeaderNames, ioResource );
1101 : int theRetVal = GET( m_pHttpSession,
1102 : OUStringToOString(
1103 : inPath, RTL_TEXTENCODING_UTF8 ).getStr(),
1104 : NeonSession_ResponseBlockReader,
1105 : true,
1106 0 : &aCtx );
1107 :
1108 0 : HandleError( theRetVal, inPath, rEnv );
1109 :
1110 0 : return uno::Reference< io::XInputStream >( xInputStream.get() );
1111 : }
1112 :
1113 0 : void NeonSession::GET( const OUString & inPath,
1114 : uno::Reference< io::XOutputStream > & ioOutputStream,
1115 : const std::vector< OUString > & inHeaderNames,
1116 : DAVResource & ioResource,
1117 : const DAVRequestEnvironment & rEnv )
1118 : throw ( std::exception )
1119 : {
1120 0 : osl::Guard< osl::Mutex > theGuard( m_aMutex );
1121 :
1122 0 : Init( rEnv );
1123 :
1124 0 : ioResource.uri = inPath;
1125 0 : ioResource.properties.clear();
1126 :
1127 0 : NeonRequestContext aCtx( ioOutputStream, inHeaderNames, ioResource );
1128 : int theRetVal = GET( m_pHttpSession,
1129 : OUStringToOString(
1130 : inPath, RTL_TEXTENCODING_UTF8 ).getStr(),
1131 : NeonSession_ResponseBlockWriter,
1132 : true,
1133 0 : &aCtx );
1134 :
1135 0 : HandleError( theRetVal, inPath, rEnv );
1136 0 : }
1137 :
1138 0 : void NeonSession::PUT( const OUString & inPath,
1139 : const uno::Reference< io::XInputStream > & inInputStream,
1140 : const DAVRequestEnvironment & rEnv )
1141 : throw ( std::exception )
1142 : {
1143 0 : osl::Guard< osl::Mutex > theGuard( m_aMutex );
1144 :
1145 0 : uno::Sequence< sal_Int8 > aDataToSend;
1146 0 : if ( !getDataFromInputStream( inInputStream, aDataToSend, false ) )
1147 0 : throw DAVException( DAVException::DAV_INVALID_ARG );
1148 :
1149 0 : Init( rEnv );
1150 :
1151 : int theRetVal = PUT( m_pHttpSession,
1152 : OUStringToOString(
1153 : inPath, RTL_TEXTENCODING_UTF8 ).getStr(),
1154 : reinterpret_cast< const char * >(
1155 0 : aDataToSend.getConstArray() ),
1156 0 : aDataToSend.getLength() );
1157 :
1158 0 : HandleError( theRetVal, inPath, rEnv );
1159 0 : }
1160 :
1161 : uno::Reference< io::XInputStream >
1162 0 : NeonSession::POST( const OUString & inPath,
1163 : const OUString & rContentType,
1164 : const OUString & rReferer,
1165 : const uno::Reference< io::XInputStream > & inInputStream,
1166 : const DAVRequestEnvironment & rEnv )
1167 : throw ( std::exception )
1168 : {
1169 0 : osl::Guard< osl::Mutex > theGuard( m_aMutex );
1170 :
1171 0 : uno::Sequence< sal_Int8 > aDataToSend;
1172 0 : if ( !getDataFromInputStream( inInputStream, aDataToSend, true ) )
1173 0 : throw DAVException( DAVException::DAV_INVALID_ARG );
1174 :
1175 0 : Init( rEnv );
1176 :
1177 0 : rtl::Reference< NeonInputStream > xInputStream( new NeonInputStream );
1178 0 : NeonRequestContext aCtx( xInputStream );
1179 : int theRetVal = POST( m_pHttpSession,
1180 : OUStringToOString(
1181 : inPath, RTL_TEXTENCODING_UTF8 ).getStr(),
1182 : reinterpret_cast< const char * >(
1183 0 : aDataToSend.getConstArray() ),
1184 : NeonSession_ResponseBlockReader,
1185 : &aCtx,
1186 : rContentType,
1187 0 : rReferer );
1188 :
1189 0 : HandleError( theRetVal, inPath, rEnv );
1190 :
1191 0 : return uno::Reference< io::XInputStream >( xInputStream.get() );
1192 : }
1193 :
1194 0 : void NeonSession::POST( const OUString & inPath,
1195 : const OUString & rContentType,
1196 : const OUString & rReferer,
1197 : const uno::Reference< io::XInputStream > & inInputStream,
1198 : uno::Reference< io::XOutputStream > & oOutputStream,
1199 : const DAVRequestEnvironment & rEnv )
1200 : throw ( std::exception )
1201 : {
1202 0 : osl::Guard< osl::Mutex > theGuard( m_aMutex );
1203 :
1204 0 : uno::Sequence< sal_Int8 > aDataToSend;
1205 0 : if ( !getDataFromInputStream( inInputStream, aDataToSend, true ) )
1206 0 : throw DAVException( DAVException::DAV_INVALID_ARG );
1207 :
1208 0 : Init( rEnv );
1209 :
1210 0 : NeonRequestContext aCtx( oOutputStream );
1211 : int theRetVal = POST( m_pHttpSession,
1212 : OUStringToOString(
1213 : inPath, RTL_TEXTENCODING_UTF8 ).getStr(),
1214 : reinterpret_cast< const char * >(
1215 0 : aDataToSend.getConstArray() ),
1216 : NeonSession_ResponseBlockWriter,
1217 : &aCtx,
1218 : rContentType,
1219 0 : rReferer );
1220 :
1221 0 : HandleError( theRetVal, inPath, rEnv );
1222 0 : }
1223 :
1224 0 : void NeonSession::MKCOL( const OUString & inPath,
1225 : const DAVRequestEnvironment & rEnv )
1226 : throw ( std::exception )
1227 : {
1228 0 : osl::Guard< osl::Mutex > theGuard( m_aMutex );
1229 :
1230 0 : Init( rEnv );
1231 :
1232 : int theRetVal = ne_mkcol( m_pHttpSession,
1233 : OUStringToOString(
1234 0 : inPath, RTL_TEXTENCODING_UTF8 ).getStr() );
1235 :
1236 0 : HandleError( theRetVal, inPath, rEnv );
1237 0 : }
1238 :
1239 0 : void NeonSession::COPY( const OUString & inSourceURL,
1240 : const OUString & inDestinationURL,
1241 : const DAVRequestEnvironment & rEnv,
1242 : bool inOverWrite )
1243 : throw ( std::exception )
1244 : {
1245 0 : osl::Guard< osl::Mutex > theGuard( m_aMutex );
1246 :
1247 0 : Init( rEnv );
1248 :
1249 0 : NeonUri theSourceUri( inSourceURL );
1250 0 : NeonUri theDestinationUri( inDestinationURL );
1251 :
1252 : int theRetVal = ne_copy( m_pHttpSession,
1253 : inOverWrite ? 1 : 0,
1254 : NE_DEPTH_INFINITE,
1255 : OUStringToOString(
1256 0 : theSourceUri.GetPath(),
1257 : RTL_TEXTENCODING_UTF8 ).getStr(),
1258 : OUStringToOString(
1259 0 : theDestinationUri.GetPath(),
1260 0 : RTL_TEXTENCODING_UTF8 ).getStr() );
1261 :
1262 0 : HandleError( theRetVal, inSourceURL, rEnv );
1263 0 : }
1264 :
1265 0 : void NeonSession::MOVE( const OUString & inSourceURL,
1266 : const OUString & inDestinationURL,
1267 : const DAVRequestEnvironment & rEnv,
1268 : bool inOverWrite )
1269 : throw ( std::exception )
1270 : {
1271 0 : osl::Guard< osl::Mutex > theGuard( m_aMutex );
1272 :
1273 0 : Init( rEnv );
1274 :
1275 0 : NeonUri theSourceUri( inSourceURL );
1276 0 : NeonUri theDestinationUri( inDestinationURL );
1277 : int theRetVal = ne_move( m_pHttpSession,
1278 : inOverWrite ? 1 : 0,
1279 : OUStringToOString(
1280 0 : theSourceUri.GetPath(),
1281 : RTL_TEXTENCODING_UTF8 ).getStr(),
1282 : OUStringToOString(
1283 0 : theDestinationUri.GetPath(),
1284 0 : RTL_TEXTENCODING_UTF8 ).getStr() );
1285 :
1286 0 : HandleError( theRetVal, inSourceURL, rEnv );
1287 0 : }
1288 :
1289 0 : void NeonSession::DESTROY( const OUString & inPath,
1290 : const DAVRequestEnvironment & rEnv )
1291 : throw ( std::exception )
1292 : {
1293 0 : osl::Guard< osl::Mutex > theGuard( m_aMutex );
1294 :
1295 0 : Init( rEnv );
1296 :
1297 : int theRetVal = ne_delete( m_pHttpSession,
1298 : OUStringToOString(
1299 0 : inPath, RTL_TEXTENCODING_UTF8 ).getStr() );
1300 :
1301 0 : HandleError( theRetVal, inPath, rEnv );
1302 0 : }
1303 :
1304 : namespace
1305 : {
1306 0 : sal_Int32 lastChanceToSendRefreshRequest( TimeValue const & rStart,
1307 : int timeout )
1308 : {
1309 : TimeValue aEnd;
1310 0 : osl_getSystemTime( &aEnd );
1311 :
1312 : // Try to estimate a safe absolute time for sending the
1313 : // lock refresh request.
1314 0 : sal_Int32 lastChanceToSendRefreshRequest = -1;
1315 0 : if ( timeout != NE_TIMEOUT_INFINITE )
1316 : {
1317 0 : sal_Int32 calltime = aEnd.Seconds - rStart.Seconds;
1318 0 : if ( calltime <= timeout )
1319 : {
1320 : lastChanceToSendRefreshRequest
1321 0 : = aEnd.Seconds + timeout - calltime;
1322 : }
1323 : else
1324 : {
1325 : OSL_TRACE( "No chance to refresh lock before timeout!" );
1326 : }
1327 : }
1328 0 : return lastChanceToSendRefreshRequest;
1329 : }
1330 :
1331 : } // namespace
1332 :
1333 : // Set new lock
1334 0 : void NeonSession::LOCK( const OUString & inPath,
1335 : ucb::Lock & rLock,
1336 : const DAVRequestEnvironment & rEnv )
1337 : throw ( std::exception )
1338 : {
1339 0 : osl::Guard< osl::Mutex > theGuard( m_aMutex );
1340 :
1341 0 : Init( rEnv );
1342 :
1343 : /* Create a depth zero, exclusive write lock, with default timeout
1344 : * (allowing a server to pick a default). token, owner and uri are
1345 : * unset. */
1346 0 : NeonLock * theLock = ne_lock_create();
1347 :
1348 : // Set the lock uri
1349 : ne_uri aUri;
1350 : ne_uri_parse( OUStringToOString( makeAbsoluteURL( inPath ),
1351 : RTL_TEXTENCODING_UTF8 ).getStr(),
1352 0 : &aUri );
1353 0 : theLock->uri = aUri;
1354 :
1355 : // Set the lock depth
1356 0 : switch( rLock.Depth )
1357 : {
1358 : case ucb::LockDepth_ZERO:
1359 0 : theLock->depth = NE_DEPTH_ZERO;
1360 0 : break;
1361 : case ucb::LockDepth_ONE:
1362 0 : theLock->depth = NE_DEPTH_ONE;
1363 0 : break;
1364 : case ucb::LockDepth_INFINITY:
1365 0 : theLock->depth = NE_DEPTH_INFINITE;
1366 0 : break;
1367 : default:
1368 0 : throw DAVException( DAVException::DAV_INVALID_ARG );
1369 : }
1370 :
1371 : // Set the lock scope
1372 0 : switch ( rLock.Scope )
1373 : {
1374 : case ucb::LockScope_EXCLUSIVE:
1375 0 : theLock->scope = ne_lockscope_exclusive;
1376 0 : break;
1377 : case ucb::LockScope_SHARED:
1378 0 : theLock->scope = ne_lockscope_shared;
1379 0 : break;
1380 : default:
1381 0 : throw DAVException( DAVException::DAV_INVALID_ARG );
1382 : }
1383 :
1384 : // Set the lock timeout
1385 0 : theLock->timeout = (long)rLock.Timeout;
1386 :
1387 : // Set the lock owner
1388 0 : OUString aValue;
1389 0 : rLock.Owner >>= aValue;
1390 : theLock->owner =
1391 : ne_strdup( OUStringToOString( aValue,
1392 0 : RTL_TEXTENCODING_UTF8 ).getStr() );
1393 : TimeValue startCall;
1394 0 : osl_getSystemTime( &startCall );
1395 :
1396 0 : int theRetVal = ne_lock( m_pHttpSession, theLock );
1397 :
1398 0 : if ( theRetVal == NE_OK )
1399 : {
1400 : m_aNeonLockStore.addLock( theLock,
1401 : this,
1402 : lastChanceToSendRefreshRequest(
1403 0 : startCall, theLock->timeout ) );
1404 :
1405 0 : uno::Sequence< OUString > aTokens( 1 );
1406 0 : aTokens[ 0 ] = OUString::createFromAscii( theLock->token );
1407 0 : rLock.LockTokens = aTokens;
1408 :
1409 : OSL_TRACE( "NeonSession::LOCK: created lock for %s. token: %s",
1410 : OUStringToOString( makeAbsoluteURL( inPath ),
1411 : RTL_TEXTENCODING_UTF8 ).getStr(),
1412 0 : theLock->token );
1413 : }
1414 : else
1415 : {
1416 0 : ne_lock_destroy( theLock );
1417 :
1418 : OSL_TRACE( "NeonSession::LOCK: obtaining lock for %s failed!",
1419 : OUStringToOString( makeAbsoluteURL( inPath ),
1420 : RTL_TEXTENCODING_UTF8 ).getStr() );
1421 : }
1422 :
1423 0 : HandleError( theRetVal, inPath, rEnv );
1424 0 : }
1425 :
1426 : // Refresh existing lock
1427 0 : sal_Int64 NeonSession::LOCK( const OUString & inPath,
1428 : sal_Int64 nTimeout,
1429 : const DAVRequestEnvironment & rEnv )
1430 : throw ( std::exception )
1431 : {
1432 0 : osl::Guard< osl::Mutex > theGuard( m_aMutex );
1433 :
1434 : // Try to get the neon lock from lock store
1435 : NeonLock * theLock
1436 0 : = m_aNeonLockStore.findByUri( makeAbsoluteURL( inPath ) );
1437 0 : if ( !theLock )
1438 0 : throw DAVException( DAVException::DAV_NOT_LOCKED );
1439 :
1440 0 : Init( rEnv );
1441 :
1442 : // refresh existing lock.
1443 0 : theLock->timeout = static_cast< long >( nTimeout );
1444 :
1445 : TimeValue startCall;
1446 0 : osl_getSystemTime( &startCall );
1447 :
1448 0 : int theRetVal = ne_lock_refresh( m_pHttpSession, theLock );
1449 :
1450 0 : if ( theRetVal == NE_OK )
1451 : {
1452 : m_aNeonLockStore.updateLock( theLock,
1453 : lastChanceToSendRefreshRequest(
1454 0 : startCall, theLock->timeout ) );
1455 : }
1456 :
1457 0 : HandleError( theRetVal, inPath, rEnv );
1458 :
1459 0 : return theLock->timeout;
1460 : }
1461 :
1462 : // Refresh existing lock
1463 0 : bool NeonSession::LOCK( NeonLock * pLock,
1464 : sal_Int32 & rlastChanceToSendRefreshRequest )
1465 : {
1466 0 : osl::Guard< osl::Mutex > theGuard( m_aMutex );
1467 :
1468 : #if OSL_DEBUG_LEVEL > 0
1469 : char * p = ne_uri_unparse( &(pLock->uri) );
1470 : OSL_TRACE( "NeonSession::LOCK: Refreshing lock for %s.", p );
1471 : ne_free( p );
1472 : #endif
1473 :
1474 : // refresh existing lock.
1475 :
1476 : TimeValue startCall;
1477 0 : osl_getSystemTime( &startCall );
1478 :
1479 0 : if ( ne_lock_refresh( m_pHttpSession, pLock ) == NE_OK )
1480 : {
1481 : rlastChanceToSendRefreshRequest
1482 0 : = lastChanceToSendRefreshRequest( startCall, pLock->timeout );
1483 :
1484 : OSL_TRACE( "Lock successfully refreshed." );
1485 0 : return true;
1486 : }
1487 : else
1488 : {
1489 : OSL_TRACE( "Lock not refreshed!" );
1490 0 : return false;
1491 0 : }
1492 : }
1493 :
1494 0 : void NeonSession::UNLOCK( const OUString & inPath,
1495 : const DAVRequestEnvironment & rEnv )
1496 : throw ( std::exception )
1497 : {
1498 0 : osl::Guard< osl::Mutex > theGuard( m_aMutex );
1499 :
1500 : // get the neon lock from lock store
1501 : NeonLock * theLock
1502 0 : = m_aNeonLockStore.findByUri( makeAbsoluteURL( inPath ) );
1503 0 : if ( !theLock )
1504 0 : throw DAVException( DAVException::DAV_NOT_LOCKED );
1505 :
1506 0 : Init( rEnv );
1507 :
1508 0 : int theRetVal = ne_unlock( m_pHttpSession, theLock );
1509 :
1510 0 : if ( theRetVal == NE_OK )
1511 : {
1512 0 : m_aNeonLockStore.removeLock( theLock );
1513 0 : ne_lock_destroy( theLock );
1514 : }
1515 : else
1516 : {
1517 : OSL_TRACE( "NeonSession::UNLOCK: unlocking of %s failed.",
1518 : OUStringToOString( makeAbsoluteURL( inPath ),
1519 : RTL_TEXTENCODING_UTF8 ).getStr() );
1520 : }
1521 :
1522 0 : HandleError( theRetVal, inPath, rEnv );
1523 0 : }
1524 :
1525 0 : bool NeonSession::UNLOCK( NeonLock * pLock )
1526 : {
1527 0 : osl::Guard< osl::Mutex > theGuard( m_aMutex );
1528 :
1529 : #if OSL_DEBUG_LEVEL > 0
1530 : char * p = ne_uri_unparse( &(pLock->uri) );
1531 : OSL_TRACE( "NeonSession::UNLOCK: Unlocking %s.", p );
1532 : ne_free( p );
1533 : #endif
1534 :
1535 0 : if ( ne_unlock( m_pHttpSession, pLock ) == NE_OK )
1536 : {
1537 : OSL_TRACE( "UNLOCK succeeded." );
1538 0 : return true;
1539 : }
1540 : else
1541 : {
1542 : OSL_TRACE( "UNLOCK failed!" );
1543 0 : return false;
1544 0 : }
1545 : }
1546 :
1547 0 : void NeonSession::abort()
1548 : throw ( std::exception )
1549 : {
1550 : SAL_INFO("ucb.ucp.webdav", "neon commands cannot be aborted");
1551 0 : }
1552 :
1553 0 : const ucbhelper::InternetProxyServer & NeonSession::getProxySettings() const
1554 : {
1555 0 : if ( m_aScheme == "http" || m_aScheme == "https" )
1556 : {
1557 : return m_rProxyDecider.getProxy( m_aScheme,
1558 : m_aHostName,
1559 0 : m_nPort );
1560 : }
1561 : else
1562 : {
1563 : return m_rProxyDecider.getProxy( m_aScheme,
1564 : OUString() /* not used */,
1565 0 : -1 /* not used */ );
1566 : }
1567 : }
1568 :
1569 : namespace {
1570 :
1571 0 : bool containsLocktoken( const uno::Sequence< ucb::Lock > & rLocks,
1572 : const char * token )
1573 : {
1574 0 : for ( sal_Int32 n = 0; n < rLocks.getLength(); ++n )
1575 : {
1576 : const uno::Sequence< OUString > & rTokens
1577 0 : = rLocks[ n ].LockTokens;
1578 0 : for ( sal_Int32 m = 0; m < rTokens.getLength(); ++m )
1579 : {
1580 0 : if ( rTokens[ m ].equalsAscii( token ) )
1581 0 : return true;
1582 : }
1583 : }
1584 0 : return false;
1585 : }
1586 :
1587 : } // namespace
1588 :
1589 0 : bool NeonSession::removeExpiredLocktoken( const OUString & inURL,
1590 : const DAVRequestEnvironment & rEnv )
1591 : {
1592 0 : NeonLock * theLock = m_aNeonLockStore.findByUri( inURL );
1593 0 : if ( !theLock )
1594 0 : return false;
1595 :
1596 : // do a lockdiscovery to check whether this lock is still valid.
1597 : try
1598 : {
1599 : // @@@ Alternative: use ne_lock_discover() => less overhead
1600 :
1601 0 : std::vector< DAVResource > aResources;
1602 0 : std::vector< OUString > aPropNames;
1603 0 : aPropNames.push_back( DAVProperties::LOCKDISCOVERY );
1604 :
1605 0 : PROPFIND( rEnv.m_aRequestURI, DAVZERO, aPropNames, aResources, rEnv );
1606 :
1607 0 : if ( aResources.empty() )
1608 0 : return false;
1609 :
1610 : std::vector< DAVPropertyValue >::const_iterator it
1611 0 : = aResources[ 0 ].properties.begin();
1612 : std::vector< DAVPropertyValue >::const_iterator end
1613 0 : = aResources[ 0 ].properties.end();
1614 :
1615 0 : while ( it != end )
1616 : {
1617 0 : if ( (*it).Name.equals( DAVProperties::LOCKDISCOVERY ) )
1618 : {
1619 0 : uno::Sequence< ucb::Lock > aLocks;
1620 0 : if ( !( (*it).Value >>= aLocks ) )
1621 0 : return false;
1622 :
1623 0 : if ( !containsLocktoken( aLocks, theLock->token ) )
1624 : {
1625 : // expired!
1626 0 : break;
1627 : }
1628 :
1629 : // still valid.
1630 0 : return false;
1631 : }
1632 0 : ++it;
1633 : }
1634 :
1635 : // No lockdiscovery prop in propfind result / locktoken not found
1636 : // in propfind result -> not locked
1637 : OSL_TRACE( "NeonSession::removeExpiredLocktoken: Removing "
1638 : " expired lock token for %s. token: %s",
1639 : OUStringToOString( inURL,
1640 : RTL_TEXTENCODING_UTF8 ).getStr(),
1641 : theLock->token );
1642 :
1643 0 : m_aNeonLockStore.removeLock( theLock );
1644 0 : ne_lock_destroy( theLock );
1645 0 : return true;
1646 : }
1647 0 : catch ( DAVException const & )
1648 : {
1649 : }
1650 0 : return false;
1651 : }
1652 :
1653 : // Common error handler
1654 0 : void NeonSession::HandleError( int nError,
1655 : const OUString & inPath,
1656 : const DAVRequestEnvironment & rEnv )
1657 : throw ( std::exception )
1658 : {
1659 0 : m_aEnv = DAVRequestEnvironment();
1660 :
1661 : // Map error code to DAVException.
1662 0 : switch ( nError )
1663 : {
1664 : case NE_OK:
1665 0 : return;
1666 :
1667 : case NE_ERROR: // Generic error
1668 : {
1669 : OUString aText = OUString::createFromAscii(
1670 0 : ne_get_error( m_pHttpSession ) );
1671 :
1672 0 : sal_uInt16 code = makeStatusCode( aText );
1673 :
1674 0 : if ( code == SC_LOCKED )
1675 : {
1676 0 : if ( m_aNeonLockStore.findByUri(
1677 0 : makeAbsoluteURL( inPath ) ) == 0 )
1678 : {
1679 : // locked by 3rd party
1680 0 : throw DAVException( DAVException::DAV_LOCKED );
1681 : }
1682 : else
1683 : {
1684 : // locked by ourself
1685 0 : throw DAVException( DAVException::DAV_LOCKED_SELF );
1686 : }
1687 : }
1688 :
1689 : // Special handling for 400 and 412 status codes, which may indicate
1690 : // that a lock previously obtained by us has been released meanwhile
1691 : // by the server. Unfortunately, RFC is not clear at this point,
1692 : // thus server implementations behave different...
1693 0 : else if ( code == SC_BAD_REQUEST || code == SC_PRECONDITION_FAILED )
1694 : {
1695 0 : if ( removeExpiredLocktoken( makeAbsoluteURL( inPath ), rEnv ) )
1696 0 : throw DAVException( DAVException::DAV_LOCK_EXPIRED );
1697 : }
1698 :
1699 0 : throw DAVException( DAVException::DAV_HTTP_ERROR, aText, code );
1700 : }
1701 : case NE_LOOKUP: // Name lookup failed.
1702 : throw DAVException( DAVException::DAV_HTTP_LOOKUP,
1703 : NeonUri::makeConnectionEndPointString(
1704 0 : m_aHostName, m_nPort ) );
1705 :
1706 : case NE_AUTH: // User authentication failed on server
1707 : throw DAVException( DAVException::DAV_HTTP_AUTH,
1708 : NeonUri::makeConnectionEndPointString(
1709 0 : m_aHostName, m_nPort ) );
1710 :
1711 : case NE_PROXYAUTH: // User authentication failed on proxy
1712 : throw DAVException( DAVException::DAV_HTTP_AUTHPROXY,
1713 : NeonUri::makeConnectionEndPointString(
1714 0 : m_aProxyName, m_nProxyPort ) );
1715 :
1716 : case NE_CONNECT: // Could not connect to server
1717 : throw DAVException( DAVException::DAV_HTTP_CONNECT,
1718 : NeonUri::makeConnectionEndPointString(
1719 0 : m_aHostName, m_nPort ) );
1720 :
1721 : case NE_TIMEOUT: // Connection timed out
1722 : throw DAVException( DAVException::DAV_HTTP_TIMEOUT,
1723 : NeonUri::makeConnectionEndPointString(
1724 0 : m_aHostName, m_nPort ) );
1725 :
1726 : case NE_FAILED: // The precondition failed
1727 : throw DAVException( DAVException::DAV_HTTP_FAILED,
1728 : NeonUri::makeConnectionEndPointString(
1729 0 : m_aHostName, m_nPort ) );
1730 :
1731 : case NE_RETRY: // Retry request (ne_end_request ONLY)
1732 : throw DAVException( DAVException::DAV_HTTP_RETRY,
1733 : NeonUri::makeConnectionEndPointString(
1734 0 : m_aHostName, m_nPort ) );
1735 :
1736 : case NE_REDIRECT:
1737 : {
1738 0 : NeonUri aUri( ne_redirect_location( m_pHttpSession ) );
1739 : throw DAVException(
1740 0 : DAVException::DAV_HTTP_REDIRECT, aUri.GetURI() );
1741 : }
1742 : default:
1743 : {
1744 : OSL_TRACE( "NeonSession::HandleError : Unknown Neon error code!" );
1745 : throw DAVException( DAVException::DAV_HTTP_ERROR,
1746 : OUString::createFromAscii(
1747 0 : ne_get_error( m_pHttpSession ) ) );
1748 : }
1749 : }
1750 : }
1751 :
1752 : namespace {
1753 :
1754 0 : void runResponseHeaderHandler( void * userdata,
1755 : const char * value )
1756 : {
1757 0 : OUString aHeader( OUString::createFromAscii( value ) );
1758 0 : sal_Int32 nPos = aHeader.indexOf( ':' );
1759 :
1760 0 : if ( nPos != -1 )
1761 : {
1762 0 : OUString aHeaderName( aHeader.copy( 0, nPos ) );
1763 :
1764 : NeonRequestContext * pCtx
1765 0 : = static_cast< NeonRequestContext * >( userdata );
1766 :
1767 : // Note: Empty vector means that all headers are requested.
1768 0 : bool bIncludeIt = ( pCtx->pHeaderNames->empty() );
1769 :
1770 0 : if ( !bIncludeIt )
1771 : {
1772 : // Check whether this header was requested.
1773 : std::vector< OUString >::const_iterator it(
1774 0 : pCtx->pHeaderNames->begin() );
1775 : const std::vector< OUString >::const_iterator end(
1776 0 : pCtx->pHeaderNames->end() );
1777 :
1778 0 : while ( it != end )
1779 : {
1780 : // header names are case insensitive
1781 0 : if ( (*it).equalsIgnoreAsciiCase( aHeaderName ) )
1782 : {
1783 0 : aHeaderName = (*it);
1784 0 : break;
1785 : }
1786 0 : ++it;
1787 : }
1788 :
1789 0 : if ( it != end )
1790 0 : bIncludeIt = true;
1791 : }
1792 :
1793 0 : if ( bIncludeIt )
1794 : {
1795 : // Create & set the PropertyValue
1796 0 : DAVPropertyValue thePropertyValue;
1797 0 : thePropertyValue.IsCaseSensitive = false;
1798 0 : thePropertyValue.Name = aHeaderName;
1799 :
1800 0 : if ( nPos < aHeader.getLength() )
1801 0 : thePropertyValue.Value <<= aHeader.copy( nPos + 1 ).trim();
1802 :
1803 : // Add the newly created PropertyValue
1804 0 : pCtx->pResource->properties.push_back( thePropertyValue );
1805 0 : }
1806 0 : }
1807 0 : }
1808 :
1809 : } // namespace
1810 :
1811 0 : int NeonSession::GET( ne_session * sess,
1812 : const char * uri,
1813 : ne_block_reader reader,
1814 : bool getheaders,
1815 : void * userdata )
1816 : {
1817 : //struct get_context ctx;
1818 0 : ne_request * req = ne_request_create( sess, "GET", uri );
1819 : int ret;
1820 :
1821 : ne_decompress * dc
1822 0 : = ne_decompress_reader( req, ne_accept_2xx, reader, userdata );
1823 :
1824 : {
1825 0 : osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex );
1826 0 : ret = ne_request_dispatch( req );
1827 : }
1828 :
1829 0 : if ( getheaders )
1830 : {
1831 0 : void *cursor = NULL;
1832 : const char *name, *value;
1833 0 : while ( ( cursor = ne_response_header_iterate(
1834 : req, cursor, &name, &value ) ) != NULL )
1835 : {
1836 : char buffer[8192];
1837 :
1838 0 : ne_snprintf(buffer, sizeof buffer, "%s: %s", name, value);
1839 0 : runResponseHeaderHandler(userdata, buffer);
1840 : }
1841 : }
1842 :
1843 0 : if ( ret == NE_OK && ne_get_status( req )->klass != 2 )
1844 0 : ret = NE_ERROR;
1845 :
1846 0 : if ( dc != 0 )
1847 0 : ne_decompress_destroy(dc);
1848 :
1849 0 : ne_request_destroy( req );
1850 0 : return ret;
1851 : }
1852 :
1853 0 : int NeonSession::PUT( ne_session * sess,
1854 : const char * uri,
1855 : const char * buffer,
1856 : size_t size)
1857 : {
1858 0 : ne_request * req = ne_request_create( sess, "PUT", uri );
1859 : int ret;
1860 :
1861 0 : ne_lock_using_resource( req, uri, 0 );
1862 0 : ne_lock_using_parent( req, uri );
1863 :
1864 0 : ne_set_request_body_buffer( req, buffer, size );
1865 :
1866 : {
1867 0 : osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex );
1868 0 : ret = ne_request_dispatch( req );
1869 : }
1870 :
1871 0 : if ( ret == NE_OK && ne_get_status( req )->klass != 2 )
1872 0 : ret = NE_ERROR;
1873 :
1874 0 : ne_request_destroy( req );
1875 0 : return ret;
1876 : }
1877 :
1878 0 : int NeonSession::POST( ne_session * sess,
1879 : const char * uri,
1880 : const char * buffer,
1881 : ne_block_reader reader,
1882 : void * userdata,
1883 : const OUString & rContentType,
1884 : const OUString & rReferer )
1885 : {
1886 0 : ne_request * req = ne_request_create( sess, "POST", uri );
1887 : //struct get_context ctx;
1888 : int ret;
1889 :
1890 0 : RequestDataMap * pData = 0;
1891 :
1892 0 : if ( !rContentType.isEmpty() || !rReferer.isEmpty() )
1893 : {
1894 : // Remember contenttype and referer. Data will be added to HTTP request
1895 : // header in 'PreSendRequest' callback.
1896 0 : pData = static_cast< RequestDataMap* >( m_pRequestData );
1897 0 : (*pData)[ req ] = RequestData( rContentType, rReferer );
1898 : }
1899 :
1900 : //ctx.total = -1;
1901 : //ctx.fd = fd;
1902 : //ctx.error = 0;
1903 : //ctx.session = sess;
1904 :
1905 : ///* Read the value of the Content-Length header into ctx.total */
1906 : //ne_add_response_header_handler( req, "Content-Length",
1907 : // ne_handle_numeric_header, &ctx.total );
1908 :
1909 0 : ne_add_response_body_reader( req, ne_accept_2xx, reader, userdata );
1910 :
1911 0 : ne_set_request_body_buffer( req, buffer, strlen( buffer ) );
1912 :
1913 : {
1914 0 : osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex );
1915 0 : ret = ne_request_dispatch( req );
1916 : }
1917 :
1918 : //if ( ctx.error )
1919 : // ret = NE_ERROR;
1920 : //else
1921 0 : if ( ret == NE_OK && ne_get_status( req )->klass != 2 )
1922 0 : ret = NE_ERROR;
1923 :
1924 0 : ne_request_destroy( req );
1925 :
1926 0 : if ( pData )
1927 : {
1928 : // Remove request data from session's list.
1929 0 : RequestDataMap::iterator it = pData->find( req );
1930 0 : if ( it != pData->end() )
1931 0 : pData->erase( it );
1932 : }
1933 :
1934 0 : return ret;
1935 : }
1936 :
1937 : bool
1938 0 : NeonSession::getDataFromInputStream(
1939 : const uno::Reference< io::XInputStream > & xStream,
1940 : uno::Sequence< sal_Int8 > & rData,
1941 : bool bAppendTrailingZeroByte )
1942 : {
1943 0 : if ( xStream.is() )
1944 : {
1945 0 : uno::Reference< io::XSeekable > xSeekable( xStream, uno::UNO_QUERY );
1946 0 : if ( xSeekable.is() )
1947 : {
1948 : try
1949 : {
1950 : sal_Int32 nSize
1951 0 : = sal::static_int_cast<sal_Int32>(xSeekable->getLength());
1952 : sal_Int32 nRead
1953 0 : = xStream->readBytes( rData, nSize );
1954 :
1955 0 : if ( nRead == nSize )
1956 : {
1957 0 : if ( bAppendTrailingZeroByte )
1958 : {
1959 0 : rData.realloc( nSize + 1 );
1960 0 : rData[ nSize ] = sal_Int8( 0 );
1961 : }
1962 0 : return true;
1963 : }
1964 : }
1965 0 : catch ( io::NotConnectedException const & )
1966 : {
1967 : // readBytes
1968 : }
1969 0 : catch ( io::BufferSizeExceededException const & )
1970 : {
1971 : // readBytes
1972 : }
1973 0 : catch ( io::IOException const & )
1974 : {
1975 : // getLength, readBytes
1976 : }
1977 : }
1978 : else
1979 : {
1980 : try
1981 : {
1982 0 : uno::Sequence< sal_Int8 > aBuffer;
1983 0 : sal_Int32 nPos = 0;
1984 :
1985 0 : sal_Int32 nRead = xStream->readSomeBytes( aBuffer, 65536 );
1986 0 : while ( nRead > 0 )
1987 : {
1988 0 : if ( rData.getLength() < ( nPos + nRead ) )
1989 0 : rData.realloc( nPos + nRead );
1990 :
1991 0 : aBuffer.realloc( nRead );
1992 0 : memcpy( static_cast<void*>( rData.getArray() + nPos ),
1993 0 : static_cast<const void*>(aBuffer.getConstArray()),
1994 0 : nRead );
1995 0 : nPos += nRead;
1996 :
1997 0 : aBuffer.realloc( 0 );
1998 0 : nRead = xStream->readSomeBytes( aBuffer, 65536 );
1999 : }
2000 :
2001 0 : if ( bAppendTrailingZeroByte )
2002 : {
2003 0 : rData.realloc( nPos + 1 );
2004 0 : rData[ nPos ] = sal_Int8( 0 );
2005 : }
2006 0 : return true;
2007 : }
2008 0 : catch ( io::NotConnectedException const & )
2009 : {
2010 : // readBytes
2011 : }
2012 0 : catch ( io::BufferSizeExceededException const & )
2013 : {
2014 : // readBytes
2015 : }
2016 0 : catch ( io::IOException const & )
2017 : {
2018 : // readBytes
2019 : }
2020 0 : }
2021 : }
2022 0 : return false;
2023 : }
2024 :
2025 : bool
2026 0 : NeonSession::isDomainMatch( const OUString& certHostName )
2027 : {
2028 0 : OUString hostName = getHostName();
2029 :
2030 0 : if (hostName.equalsIgnoreAsciiCase( certHostName ) )
2031 0 : return true;
2032 :
2033 0 : if ( certHostName.startsWith( "*" ) &&
2034 0 : hostName.getLength() >= certHostName.getLength() )
2035 : {
2036 0 : OUString cmpStr = certHostName.copy( 1 );
2037 :
2038 0 : if ( hostName.matchIgnoreAsciiCase(
2039 0 : cmpStr, hostName.getLength() - cmpStr.getLength() ) )
2040 0 : return true;
2041 : }
2042 0 : return false;
2043 : }
2044 :
2045 0 : OUString NeonSession::makeAbsoluteURL( OUString const & rURL ) const
2046 : {
2047 : try
2048 : {
2049 : // Is URL relative or already absolute?
2050 0 : if ( !rURL.isEmpty() && rURL[ 0 ] != '/' )
2051 : {
2052 : // absolute.
2053 0 : return OUString( rURL );
2054 : }
2055 : else
2056 : {
2057 : ne_uri aUri;
2058 0 : memset( &aUri, 0, sizeof( aUri ) );
2059 :
2060 0 : ne_fill_server_uri( m_pHttpSession, &aUri );
2061 : aUri.path
2062 : = ne_strdup( OUStringToOString(
2063 0 : rURL, RTL_TEXTENCODING_UTF8 ).getStr() );
2064 0 : NeonUri aNeonUri( &aUri );
2065 0 : ne_uri_free( &aUri );
2066 0 : return aNeonUri.GetURI();
2067 : }
2068 : }
2069 0 : catch ( DAVException const & )
2070 : {
2071 : }
2072 : // error.
2073 0 : return OUString();
2074 6 : }
2075 :
2076 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|