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