1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "SerfRequestProcessor.hxx"
23 #include "SerfCallbacks.hxx"
24 #include "SerfSession.hxx"
25 #include "SerfPropFindReqProcImpl.hxx"
26 #include "SerfPropPatchReqProcImpl.hxx"
27 #include "SerfGetReqProcImpl.hxx"
28 #include "SerfHeadReqProcImpl.hxx"
29 #include "SerfPutReqProcImpl.hxx"
30 #include "SerfPostReqProcImpl.hxx"
31 #include "SerfDeleteReqProcImpl.hxx"
32 #include "SerfMkColReqProcImpl.hxx"
33 #include "SerfCopyReqProcImpl.hxx"
34 #include "SerfMoveReqProcImpl.hxx"
35 #include "SerfLockReqProcImpl.hxx"
36 #include "SerfUnlockReqProcImpl.hxx"
38 #include <apr_strings.h>
40 namespace http_dav_ucp
43 SerfRequestProcessor::SerfRequestProcessor( SerfSession
& rSerfSession
,
44 const OUString
& inPath
,
45 const bool bUseChunkedEncoding
)
46 : mrSerfSession( rSerfSession
)
48 , mbUseChunkedEncoding( bUseChunkedEncoding
)
53 , mbProcessingDone( false )
55 , mnHTTPStatusCode( SC_NONE
)
56 , mHTTPStatusCodeText()
58 , mnSuccessfulCredentialAttempts( 0 )
59 , mbInputOfCredentialsAborted( false )
60 , mbSetupSerfRequestCalled( false )
61 , mbAcceptSerfResponseCalled( false )
62 , mbHandleSerfResponseCalled( false )
64 mPathStr
= apr_pstrdup( mrSerfSession
.getAprPool(),
65 OUStringToOString( inPath
, RTL_TEXTENCODING_UTF8
).getStr() );
68 SerfRequestProcessor::~SerfRequestProcessor()
71 delete mpDAVException
;
74 void SerfRequestProcessor::prepareProcessor()
76 delete mpDAVException
;
78 mnHTTPStatusCode
= SC_NONE
;
79 mHTTPStatusCodeText
.clear();
80 mRedirectLocation
.clear();
82 mnSuccessfulCredentialAttempts
= 0;
83 mbInputOfCredentialsAborted
= false;
84 mbSetupSerfRequestCalled
= false;
85 mbAcceptSerfResponseCalled
= false;
86 mbHandleSerfResponseCalled
= false;
89 // PROPFIND - allprop & named
90 bool SerfRequestProcessor::processPropFind( const Depth inDepth
,
91 const std::vector
< OUString
> & inPropNames
,
92 std::vector
< DAVResource
> & ioResources
,
93 apr_status_t
& outSerfStatus
)
95 mpProcImpl
= new SerfPropFindReqProcImpl( mPathStr
,
96 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
100 outSerfStatus
= runProcessor();
102 return outSerfStatus
== APR_SUCCESS
;
105 // PROPFIND - property names
106 bool SerfRequestProcessor::processPropFind( const Depth inDepth
,
107 std::vector
< DAVResourceInfo
> & ioResInfo
,
108 apr_status_t
& outSerfStatus
)
110 mpProcImpl
= new SerfPropFindReqProcImpl( mPathStr
,
111 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
114 outSerfStatus
= runProcessor();
116 return outSerfStatus
== APR_SUCCESS
;
120 bool SerfRequestProcessor::processPropPatch( const std::vector
< ProppatchValue
> & inProperties
,
121 apr_status_t
& outSerfStatus
)
123 mpProcImpl
= new SerfPropPatchReqProcImpl( mPathStr
,
124 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
126 outSerfStatus
= runProcessor();
128 return outSerfStatus
== APR_SUCCESS
;
132 bool SerfRequestProcessor::processGet( const com::sun::star::uno::Reference
< SerfInputStream
>& xioInStrm
,
133 apr_status_t
& outSerfStatus
)
135 mpProcImpl
= new SerfGetReqProcImpl( mPathStr
,
136 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
138 outSerfStatus
= runProcessor();
140 return outSerfStatus
== APR_SUCCESS
;
143 // GET inclusive header fields
144 bool SerfRequestProcessor::processGet( const com::sun::star::uno::Reference
< SerfInputStream
>& xioInStrm
,
145 const std::vector
< OUString
> & inHeaderNames
,
146 DAVResource
& ioResource
,
147 apr_status_t
& outSerfStatus
)
149 mpProcImpl
= new SerfGetReqProcImpl( mPathStr
,
150 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
154 outSerfStatus
= runProcessor();
156 return outSerfStatus
== APR_SUCCESS
;
160 bool SerfRequestProcessor::processGet( const com::sun::star::uno::Reference
< com::sun::star::io::XOutputStream
>& xioOutStrm
,
161 apr_status_t
& outSerfStatus
)
163 mpProcImpl
= new SerfGetReqProcImpl( mPathStr
,
164 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
166 outSerfStatus
= runProcessor();
168 return outSerfStatus
== APR_SUCCESS
;
171 // GET inclusive header fields
172 bool SerfRequestProcessor::processGet( const com::sun::star::uno::Reference
< com::sun::star::io::XOutputStream
>& xioOutStrm
,
173 const std::vector
< OUString
> & inHeaderNames
,
174 DAVResource
& ioResource
,
175 apr_status_t
& outSerfStatus
)
177 mpProcImpl
= new SerfGetReqProcImpl( mPathStr
,
178 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
182 outSerfStatus
= runProcessor();
184 return outSerfStatus
== APR_SUCCESS
;
188 bool SerfRequestProcessor::processHead( const std::vector
< OUString
> & inHeaderNames
,
189 DAVResource
& ioResource
,
190 apr_status_t
& outSerfStatus
)
192 mpProcImpl
= new SerfHeadReqProcImpl( mPathStr
,
193 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
196 outSerfStatus
= runProcessor();
198 return outSerfStatus
== APR_SUCCESS
;
202 bool SerfRequestProcessor::processPut( const char* inData
,
203 apr_size_t inDataLen
,
204 apr_status_t
& outSerfStatus
)
206 // get the lock from lock store
207 const OUString
sToken(
208 apr_environment::AprEnv::getAprEnv()->getSerfLockStore()->getLockToken(
209 OUString::createFromAscii(mPathStr
)) );
211 mpProcImpl
= new SerfPutReqProcImpl( mPathStr
,
212 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
216 outSerfStatus
= runProcessor();
218 return outSerfStatus
== APR_SUCCESS
;
222 bool SerfRequestProcessor::processPost( const char* inData
,
223 apr_size_t inDataLen
,
224 const OUString
& inContentType
,
225 const OUString
& inReferer
,
226 const com::sun::star::uno::Reference
< SerfInputStream
>& xioInStrm
,
227 apr_status_t
& outSerfStatus
)
229 mContentType
= apr_pstrdup( mrSerfSession
.getAprPool(),
230 OUStringToOString( inContentType
, RTL_TEXTENCODING_UTF8
).getStr() );
231 mReferer
= apr_pstrdup( mrSerfSession
.getAprPool(),
232 OUStringToOString( inReferer
, RTL_TEXTENCODING_UTF8
).getStr() );
233 mpProcImpl
= new SerfPostReqProcImpl( mPathStr
,
234 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
240 outSerfStatus
= runProcessor();
242 return outSerfStatus
== APR_SUCCESS
;
246 bool SerfRequestProcessor::processPost( const char* inData
,
247 apr_size_t inDataLen
,
248 const OUString
& inContentType
,
249 const OUString
& inReferer
,
250 const com::sun::star::uno::Reference
< com::sun::star::io::XOutputStream
>& xioOutStrm
,
251 apr_status_t
& outSerfStatus
)
253 mContentType
= apr_pstrdup( mrSerfSession
.getAprPool(),
254 OUStringToOString( inContentType
, RTL_TEXTENCODING_UTF8
).getStr() );
255 mReferer
= apr_pstrdup( mrSerfSession
.getAprPool(),
256 OUStringToOString( inReferer
, RTL_TEXTENCODING_UTF8
).getStr() );
257 mpProcImpl
= new SerfPostReqProcImpl( mPathStr
,
258 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
264 outSerfStatus
= runProcessor();
266 return outSerfStatus
== APR_SUCCESS
;
270 bool SerfRequestProcessor::processDelete( apr_status_t
& outSerfStatus
)
272 mpProcImpl
= new SerfDeleteReqProcImpl( mPathStr
,
273 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
);
274 outSerfStatus
= runProcessor();
276 return outSerfStatus
== APR_SUCCESS
;
280 bool SerfRequestProcessor::processMkCol( apr_status_t
& outSerfStatus
)
282 mpProcImpl
= new SerfMkColReqProcImpl( mPathStr
,
283 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
);
284 outSerfStatus
= runProcessor();
286 return outSerfStatus
== APR_SUCCESS
;
290 bool SerfRequestProcessor::processCopy( const OUString
& inDestinationPath
,
291 const bool inOverwrite
,
292 apr_status_t
& outSerfStatus
)
294 mDestPathStr
= apr_pstrdup( mrSerfSession
.getAprPool(),
295 OUStringToOString( inDestinationPath
, RTL_TEXTENCODING_UTF8
).getStr() );
296 mpProcImpl
= new SerfCopyReqProcImpl( mPathStr
,
297 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
300 outSerfStatus
= runProcessor();
302 return outSerfStatus
== APR_SUCCESS
;
306 bool SerfRequestProcessor::processMove( const OUString
& inDestinationPath
,
307 const bool inOverwrite
,
308 apr_status_t
& outSerfStatus
)
310 mDestPathStr
= apr_pstrdup( mrSerfSession
.getAprPool(),
311 OUStringToOString( inDestinationPath
, RTL_TEXTENCODING_UTF8
).getStr() );
312 mpProcImpl
= new SerfMoveReqProcImpl( mPathStr
,
313 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
316 outSerfStatus
= runProcessor();
318 return outSerfStatus
== APR_SUCCESS
;
322 bool SerfRequestProcessor::processLock( const css::ucb::Lock
& rLock
, sal_Int32
*plastChanceToSendRefreshRequest
)
324 mpProcImpl
= new SerfLockReqProcImpl( mPathStr
,
325 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
328 plastChanceToSendRefreshRequest
);
330 return runProcessor() == APR_SUCCESS
;
333 bool SerfRequestProcessor::processUnlock()
335 // get the lock from lock store
336 const OUString
sToken(
337 apr_environment::AprEnv::getAprEnv()->getSerfLockStore()->getLockToken(
338 OUString::createFromAscii(mPathStr
)) );
339 if ( sToken
.isEmpty() )
340 throw DAVException( DAVException::DAV_NOT_LOCKED
);
342 mpProcImpl
= new SerfUnlockReqProcImpl( mPathStr
,
343 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
346 return runProcessor() == APR_SUCCESS
;
349 apr_status_t
SerfRequestProcessor::runProcessor()
353 // activate chunked encoding, if requested
354 if ( mbUseChunkedEncoding
)
356 mpProcImpl
->activateChunkedEncoding();
359 // create serf request
360 serf_connection_request_create( mrSerfSession
.getSerfConnection(),
364 // perform serf request
365 mbProcessingDone
= false;
366 apr_status_t status
= APR_SUCCESS
;
367 serf_context_t
* pSerfContext
= mrSerfSession
.getSerfContext();
368 apr_pool_t
* pAprPool
= mrSerfSession
.getAprPool();
371 status
= serf_context_run( pSerfContext
,
372 SERF_DURATION_FOREVER
,
374 if ( APR_STATUS_IS_TIMEUP( status
) )
378 if ( status
!= APR_SUCCESS
)
382 if ( mbProcessingDone
)
388 postprocessProcessor( status
);
393 void SerfRequestProcessor::postprocessProcessor( const apr_status_t inStatus
)
395 if ( inStatus
== APR_SUCCESS
)
403 case SERF_ERROR_AUTHN_FAILED
:
404 // general error; <mnHTTPStatusCode> provides more information
406 switch ( mnHTTPStatusCode
)
409 if ( !mbSetupSerfRequestCalled
)
411 mpDAVException
= new DAVException( DAVException::DAV_HTTP_LOOKUP
,
412 SerfUri::makeConnectionEndPointString( mrSerfSession
.getHostName(),
413 mrSerfSession
.getPort() ) );
415 else if ( mbInputOfCredentialsAborted
)
417 mpDAVException
= new DAVException( DAVException::DAV_HTTP_NOAUTH
,
418 SerfUri::makeConnectionEndPointString( mrSerfSession
.getHostName(),
419 mrSerfSession
.getPort() ) );
423 mpDAVException
= new DAVException( DAVException::DAV_HTTP_ERROR
,
428 case SC_MOVED_PERMANENTLY
:
429 case SC_MOVED_TEMPORARILY
:
431 case SC_TEMPORARY_REDIRECT
:
432 mpDAVException
= new DAVException( DAVException::DAV_HTTP_REDIRECT
,
436 mpDAVException
= new DAVException( DAVException::DAV_HTTP_ERROR
,
445 mpDAVException
= new DAVException( DAVException::DAV_HTTP_ERROR
);
451 apr_status_t
SerfRequestProcessor::provideSerfCredentials( char ** outUsername
,
453 serf_request_t
* inRequest
,
455 const char *inAuthProtocol
,
457 apr_pool_t
*inAprPool
)
459 // as each successful provided credentials are tried twice - see below - the
460 // number of real attempts is half of the value of <mnSuccessfulCredentialAttempts>
461 if ( (mnSuccessfulCredentialAttempts
/ 2) >= 5 ||
462 mbInputOfCredentialsAborted
)
464 mbInputOfCredentialsAborted
= true;
465 return SERF_ERROR_AUTHN_FAILED
;
468 // because serf keeps credentials only for a connection in case of digest authentication
469 // we give each successful provided credentials a second try in order to workaround the
470 // situation that the connection for which the credentials have been provided has been closed
471 // before the provided credentials could be applied for the request.
472 apr_status_t status
= mrSerfSession
.provideSerfCredentials( (mnSuccessfulCredentialAttempts
% 2) == 1,
480 if ( status
!= APR_SUCCESS
)
482 mbInputOfCredentialsAborted
= true;
486 ++mnSuccessfulCredentialAttempts
;
492 apr_status_t
SerfRequestProcessor::setupSerfRequest( serf_request_t
* inSerfRequest
,
493 serf_bucket_t
** outSerfRequestBucket
,
494 serf_response_acceptor_t
* outSerfResponseAcceptor
,
495 void ** outSerfResponseAcceptorBaton
,
496 serf_response_handler_t
* outSerfResponseHandler
,
497 void ** outSerfResponseHandlerBaton
,
498 apr_pool_t
* /*inAprPool*/ )
500 mbSetupSerfRequestCalled
= true;
501 *outSerfRequestBucket
= mpProcImpl
->createSerfRequestBucket( inSerfRequest
);
503 // apply callbacks for accepting response and handling response
504 *outSerfResponseAcceptor
= Serf_AcceptResponse
;
505 *outSerfResponseAcceptorBaton
= this;
506 *outSerfResponseHandler
= Serf_HandleResponse
;
507 *outSerfResponseHandlerBaton
= this;
512 serf_bucket_t
* SerfRequestProcessor::acceptSerfResponse( serf_request_t
* inSerfRequest
,
513 serf_bucket_t
* inSerfStreamBucket
,
514 apr_pool_t
* inAprPool
)
516 mbAcceptSerfResponseCalled
= true;
517 return mrSerfSession
.acceptSerfResponse( inSerfRequest
,
522 apr_status_t
SerfRequestProcessor::handleSerfResponse( serf_request_t
* inSerfRequest
,
523 serf_bucket_t
* inSerfResponseBucket
,
524 apr_pool_t
* inAprPool
)
526 mbHandleSerfResponseCalled
= true;
528 // some general response handling and error handling
530 if ( !inSerfResponseBucket
)
532 /* A NULL response can come back if the request failed completely */
533 mbProcessingDone
= true;
538 apr_status_t status
= serf_bucket_response_status( inSerfResponseBucket
, &sl
);
541 mbProcessingDone
= false; // allow another try in order to get a response
544 // TODO - check, if response status code handling is correct
545 mnHTTPStatusCode
= ( sl
.version
!= 0 && sl
.code
>= 0 )
546 ? static_cast< sal_uInt16
>( sl
.code
)
550 mHTTPStatusCodeText
= OUString::createFromAscii( sl
.reason
);
552 if ( ( sl
.version
== 0 || sl
.code
< 0 ) ||
553 mnHTTPStatusCode
>= 300 )
555 if ( mnHTTPStatusCode
== 301 ||
556 mnHTTPStatusCode
== 302 ||
557 mnHTTPStatusCode
== 303 ||
558 mnHTTPStatusCode
== 307 )
560 // new location for certain redirections
561 serf_bucket_t
*headers
= serf_bucket_response_get_headers( inSerfResponseBucket
);
562 const char* location
= serf_bucket_headers_get( headers
, "Location" );
565 mRedirectLocation
= OUString::createFromAscii( location
);
567 mbProcessingDone
= true;
570 else if ( mrSerfSession
.isHeadRequestInProgress() &&
571 ( mnHTTPStatusCode
== 401 || mnHTTPStatusCode
== 407 ) )
573 // keep going as authentication is not required on HEAD request.
574 // the response already contains header fields.
578 mbProcessingDone
= true;
584 // request specific processing of the response bucket
585 apr_status_t status
= APR_SUCCESS
;
586 mbProcessingDone
= mpProcImpl
->processSerfResponseBucket( inSerfRequest
,
587 inSerfResponseBucket
,
594 } // namespace http_dav_ucp
596 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */