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