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>
21 #include <SerfRequestProcessorImpl.hxx>
22 #include <SerfRequestProcessorImplFac.hxx>
23 #include <SerfCallbacks.hxx>
24 #include <SerfSession.hxx>
26 #include <apr_strings.h>
28 namespace http_dav_ucp
31 SerfRequestProcessor::SerfRequestProcessor( SerfSession
& rSerfSession
,
32 const rtl::OUString
& inPath
,
33 const bool bUseChunkedEncoding
)
34 : mrSerfSession( rSerfSession
)
36 , mbUseChunkedEncoding( bUseChunkedEncoding
)
41 , mbProcessingDone( false )
43 , mnHTTPStatusCode( SC_NONE
)
44 , mHTTPStatusCodeText()
46 , mnSuccessfulCredentialAttempts( 0 )
47 , mbInputOfCredentialsAborted( false )
48 , mbSetupSerfRequestCalled( false )
49 , mbAcceptSerfResponseCalled( false )
50 , mbHandleSerfResponseCalled( false )
52 mPathStr
= apr_pstrdup( mrSerfSession
.getAprPool(),
53 rtl::OUStringToOString( inPath
, RTL_TEXTENCODING_UTF8
) );
56 SerfRequestProcessor::~SerfRequestProcessor()
59 delete mpDAVException
;
62 void SerfRequestProcessor::prepareProcessor()
64 delete mpDAVException
;
66 mnHTTPStatusCode
= SC_NONE
;
67 mHTTPStatusCodeText
= rtl::OUString();
68 mRedirectLocation
= rtl::OUString();
70 mnSuccessfulCredentialAttempts
= 0;
71 mbInputOfCredentialsAborted
= false;
72 mbSetupSerfRequestCalled
= false;
73 mbAcceptSerfResponseCalled
= false;
74 mbHandleSerfResponseCalled
= false;
77 // PROPFIND - allprop & named
78 bool SerfRequestProcessor::processPropFind( const Depth inDepth
,
79 const std::vector
< ::rtl::OUString
> & inPropNames
,
80 std::vector
< DAVResource
> & ioResources
,
81 apr_status_t
& outSerfStatus
)
83 mpProcImpl
= createPropFindReqProcImpl( mPathStr
,
84 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
88 outSerfStatus
= runProcessor();
90 return outSerfStatus
== APR_SUCCESS
;
93 // PROPFIND - property names
94 bool SerfRequestProcessor::processPropFind( const Depth inDepth
,
95 std::vector
< DAVResourceInfo
> & ioResInfo
,
96 apr_status_t
& outSerfStatus
)
98 mpProcImpl
= createPropFindReqProcImpl( mPathStr
,
99 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
102 outSerfStatus
= runProcessor();
104 return outSerfStatus
== APR_SUCCESS
;
108 bool SerfRequestProcessor::processPropPatch( const std::vector
< ProppatchValue
> & inProperties
,
109 apr_status_t
& outSerfStatus
)
111 mpProcImpl
= createPropPatchReqProcImpl( mPathStr
,
112 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
114 outSerfStatus
= runProcessor();
116 return outSerfStatus
== APR_SUCCESS
;
120 bool SerfRequestProcessor::processGet( const com::sun::star::uno::Reference
< SerfInputStream
>& xioInStrm
,
121 apr_status_t
& outSerfStatus
)
123 mpProcImpl
= createGetReqProcImpl( mPathStr
,
124 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
126 outSerfStatus
= runProcessor();
128 return outSerfStatus
== APR_SUCCESS
;
131 // GET inclusive header fields
132 bool SerfRequestProcessor::processGet( const com::sun::star::uno::Reference
< SerfInputStream
>& xioInStrm
,
133 const std::vector
< ::rtl::OUString
> & inHeaderNames
,
134 DAVResource
& ioResource
,
135 apr_status_t
& outSerfStatus
)
137 mpProcImpl
= createGetReqProcImpl( mPathStr
,
138 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
142 outSerfStatus
= runProcessor();
144 return outSerfStatus
== APR_SUCCESS
;
148 bool SerfRequestProcessor::processGet( const com::sun::star::uno::Reference
< com::sun::star::io::XOutputStream
>& xioOutStrm
,
149 apr_status_t
& outSerfStatus
)
151 mpProcImpl
= createGetReqProcImpl( mPathStr
,
152 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
154 outSerfStatus
= runProcessor();
156 return outSerfStatus
== APR_SUCCESS
;
159 // GET inclusive header fields
160 bool SerfRequestProcessor::processGet( const com::sun::star::uno::Reference
< com::sun::star::io::XOutputStream
>& xioOutStrm
,
161 const std::vector
< ::rtl::OUString
> & inHeaderNames
,
162 DAVResource
& ioResource
,
163 apr_status_t
& outSerfStatus
)
165 mpProcImpl
= createGetReqProcImpl( mPathStr
,
166 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
170 outSerfStatus
= runProcessor();
172 return outSerfStatus
== APR_SUCCESS
;
176 bool SerfRequestProcessor::processHead( const std::vector
< ::rtl::OUString
> & inHeaderNames
,
177 DAVResource
& ioResource
,
178 apr_status_t
& outSerfStatus
)
180 mpProcImpl
= createHeadReqProcImpl( mPathStr
,
181 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
184 outSerfStatus
= runProcessor();
186 return outSerfStatus
== APR_SUCCESS
;
190 bool SerfRequestProcessor::processPut( const char* inData
,
191 apr_size_t inDataLen
,
192 apr_status_t
& outSerfStatus
)
194 mpProcImpl
= createPutReqProcImpl( mPathStr
,
195 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
198 outSerfStatus
= runProcessor();
200 return outSerfStatus
== APR_SUCCESS
;
204 bool SerfRequestProcessor::processPost( const char* inData
,
205 apr_size_t inDataLen
,
206 const rtl::OUString
& inContentType
,
207 const rtl::OUString
& inReferer
,
208 const com::sun::star::uno::Reference
< SerfInputStream
>& xioInStrm
,
209 apr_status_t
& outSerfStatus
)
211 mContentType
= apr_pstrdup( mrSerfSession
.getAprPool(),
212 rtl::OUStringToOString( inContentType
, RTL_TEXTENCODING_UTF8
) );
213 mReferer
= apr_pstrdup( mrSerfSession
.getAprPool(),
214 rtl::OUStringToOString( inReferer
, RTL_TEXTENCODING_UTF8
) );
215 mpProcImpl
= createPostReqProcImpl( mPathStr
,
216 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
222 outSerfStatus
= runProcessor();
224 return outSerfStatus
== APR_SUCCESS
;
228 bool SerfRequestProcessor::processPost( const char* inData
,
229 apr_size_t inDataLen
,
230 const rtl::OUString
& inContentType
,
231 const rtl::OUString
& inReferer
,
232 const com::sun::star::uno::Reference
< com::sun::star::io::XOutputStream
>& xioOutStrm
,
233 apr_status_t
& outSerfStatus
)
235 mContentType
= apr_pstrdup( mrSerfSession
.getAprPool(),
236 rtl::OUStringToOString( inContentType
, RTL_TEXTENCODING_UTF8
) );
237 mReferer
= apr_pstrdup( mrSerfSession
.getAprPool(),
238 rtl::OUStringToOString( inReferer
, RTL_TEXTENCODING_UTF8
) );
239 mpProcImpl
= createPostReqProcImpl( mPathStr
,
240 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
246 outSerfStatus
= runProcessor();
248 return outSerfStatus
== APR_SUCCESS
;
252 bool SerfRequestProcessor::processDelete( apr_status_t
& outSerfStatus
)
254 mpProcImpl
= createDeleteReqProcImpl( mPathStr
,
255 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
);
256 outSerfStatus
= runProcessor();
258 return outSerfStatus
== APR_SUCCESS
;
262 bool SerfRequestProcessor::processMkCol( apr_status_t
& outSerfStatus
)
264 mpProcImpl
= createMkColReqProcImpl( mPathStr
,
265 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
);
266 outSerfStatus
= runProcessor();
268 return outSerfStatus
== APR_SUCCESS
;
272 bool SerfRequestProcessor::processCopy( const rtl::OUString
& inDestinationPath
,
273 const bool inOverwrite
,
274 apr_status_t
& outSerfStatus
)
276 mDestPathStr
= apr_pstrdup( mrSerfSession
.getAprPool(),
277 rtl::OUStringToOString( inDestinationPath
, RTL_TEXTENCODING_UTF8
) );
278 mpProcImpl
= createCopyReqProcImpl( mPathStr
,
279 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
282 outSerfStatus
= runProcessor();
284 return outSerfStatus
== APR_SUCCESS
;
288 bool SerfRequestProcessor::processMove( const rtl::OUString
& inDestinationPath
,
289 const bool inOverwrite
,
290 apr_status_t
& outSerfStatus
)
292 mDestPathStr
= apr_pstrdup( mrSerfSession
.getAprPool(),
293 rtl::OUStringToOString( inDestinationPath
, RTL_TEXTENCODING_UTF8
) );
294 mpProcImpl
= createMoveReqProcImpl( mPathStr
,
295 mrSerfSession
.getRequestEnvironment().m_aRequestHeaders
,
298 outSerfStatus
= runProcessor();
300 return outSerfStatus
== APR_SUCCESS
;
303 apr_status_t
SerfRequestProcessor::runProcessor()
307 // activate chunked encoding, if requested
308 if ( mbUseChunkedEncoding
)
310 mpProcImpl
->activateChunkedEncoding();
313 // create serf request
314 serf_connection_request_create( mrSerfSession
.getSerfConnection(),
318 // perform serf request
319 mbProcessingDone
= false;
320 apr_status_t status
= APR_SUCCESS
;
321 serf_context_t
* pSerfContext
= mrSerfSession
.getSerfContext();
322 apr_pool_t
* pAprPool
= mrSerfSession
.getAprPool();
325 status
= serf_context_run( pSerfContext
,
326 SERF_DURATION_FOREVER
,
328 if ( APR_STATUS_IS_TIMEUP( status
) )
332 if ( status
!= APR_SUCCESS
)
336 if ( mbProcessingDone
)
342 postprocessProcessor( status
);
347 void SerfRequestProcessor::postprocessProcessor( const apr_status_t inStatus
)
349 if ( inStatus
== APR_SUCCESS
)
357 case SERF_ERROR_AUTHN_FAILED
:
358 // general error; <mnHTTPStatusCode> provides more information
360 switch ( mnHTTPStatusCode
)
363 if ( !mbSetupSerfRequestCalled
)
365 mpDAVException
= new DAVException( DAVException::DAV_HTTP_LOOKUP
,
366 SerfUri::makeConnectionEndPointString( mrSerfSession
.getHostName(),
367 mrSerfSession
.getPort() ) );
369 else if ( mbInputOfCredentialsAborted
)
371 mpDAVException
= new DAVException( DAVException::DAV_HTTP_NOAUTH
,
372 SerfUri::makeConnectionEndPointString( mrSerfSession
.getHostName(),
373 mrSerfSession
.getPort() ) );
377 mpDAVException
= new DAVException( DAVException::DAV_HTTP_ERROR
,
382 case SC_MOVED_PERMANENTLY
:
383 case SC_MOVED_TEMPORARILY
:
385 case SC_TEMPORARY_REDIRECT
:
386 mpDAVException
= new DAVException( DAVException::DAV_HTTP_REDIRECT
,
390 mpDAVException
= new DAVException( DAVException::DAV_HTTP_ERROR
,
399 mpDAVException
= new DAVException( DAVException::DAV_HTTP_ERROR
);
405 apr_status_t
SerfRequestProcessor::provideSerfCredentials( char ** outUsername
,
407 serf_request_t
* inRequest
,
409 const char *inAuthProtocol
,
411 apr_pool_t
*inAprPool
)
413 // as each successful provided credentials are tried twice - see below - the
414 // number of real attempts is half of the value of <mnSuccessfulCredentialAttempts>
415 if ( (mnSuccessfulCredentialAttempts
/ 2) >= 5 ||
416 mbInputOfCredentialsAborted
)
418 mbInputOfCredentialsAborted
= true;
419 return SERF_ERROR_AUTHN_FAILED
;
422 // because serf keeps credentials only for a connection in case of digest authentication
423 // we give each successful provided credentials a second try in order to workaround the
424 // situation that the connection for which the credentials have been provided has been closed
425 // before the provided credentials could be applied for the request.
426 apr_status_t status
= mrSerfSession
.provideSerfCredentials( (mnSuccessfulCredentialAttempts
% 2) == 1,
434 if ( status
!= APR_SUCCESS
)
436 mbInputOfCredentialsAborted
= true;
440 ++mnSuccessfulCredentialAttempts
;
446 apr_status_t
SerfRequestProcessor::setupSerfRequest( serf_request_t
* inSerfRequest
,
447 serf_bucket_t
** outSerfRequestBucket
,
448 serf_response_acceptor_t
* outSerfResponseAcceptor
,
449 void ** outSerfResponseAcceptorBaton
,
450 serf_response_handler_t
* outSerfResponseHandler
,
451 void ** outSerfResponseHandlerBaton
,
452 apr_pool_t
* /*inAprPool*/ )
454 mbSetupSerfRequestCalled
= true;
455 *outSerfRequestBucket
= mpProcImpl
->createSerfRequestBucket( inSerfRequest
);
457 // apply callbacks for accepting response and handling response
458 *outSerfResponseAcceptor
= Serf_AcceptResponse
;
459 *outSerfResponseAcceptorBaton
= this;
460 *outSerfResponseHandler
= Serf_HandleResponse
;
461 *outSerfResponseHandlerBaton
= this;
466 serf_bucket_t
* SerfRequestProcessor::acceptSerfResponse( serf_request_t
* inSerfRequest
,
467 serf_bucket_t
* inSerfStreamBucket
,
468 apr_pool_t
* inAprPool
)
470 mbAcceptSerfResponseCalled
= true;
471 return mrSerfSession
.acceptSerfResponse( inSerfRequest
,
476 apr_status_t
SerfRequestProcessor::handleSerfResponse( serf_request_t
* inSerfRequest
,
477 serf_bucket_t
* inSerfResponseBucket
,
478 apr_pool_t
* inAprPool
)
480 mbHandleSerfResponseCalled
= true;
482 // some general response handling and error handling
484 if ( !inSerfResponseBucket
)
486 /* A NULL response can come back if the request failed completely */
487 mbProcessingDone
= true;
492 apr_status_t status
= serf_bucket_response_status( inSerfResponseBucket
, &sl
);
495 mbProcessingDone
= false; // allow another try in order to get a response
498 // TODO - check, if response status code handling is correct
499 mnHTTPStatusCode
= ( sl
.version
!= 0 && sl
.code
>= 0 )
500 ? static_cast< sal_uInt16
>( sl
.code
)
504 mHTTPStatusCodeText
= ::rtl::OUString::createFromAscii( sl
.reason
);
506 if ( ( sl
.version
== 0 || sl
.code
< 0 ) ||
507 mnHTTPStatusCode
>= 300 )
509 if ( mnHTTPStatusCode
== 301 ||
510 mnHTTPStatusCode
== 302 ||
511 mnHTTPStatusCode
== 303 ||
512 mnHTTPStatusCode
== 307 )
514 // new location for certain redirections
515 serf_bucket_t
*headers
= serf_bucket_response_get_headers( inSerfResponseBucket
);
516 const char* location
= serf_bucket_headers_get( headers
, "Location" );
519 mRedirectLocation
= rtl::OUString::createFromAscii( location
);
521 mbProcessingDone
= true;
524 else if ( mrSerfSession
.isHeadRequestInProgress() &&
525 ( mnHTTPStatusCode
== 401 || mnHTTPStatusCode
== 407 ) )
527 // keep going as authentication is not required on HEAD request.
528 // the response already contains header fields.
532 mbProcessingDone
= true;
538 // request specific processing of the response bucket
539 apr_status_t status
= APR_SUCCESS
;
540 mbProcessingDone
= mpProcImpl
->processSerfResponseBucket( inSerfRequest
,
541 inSerfResponseBucket
,
548 } // namespace http_dav_ucp
550 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */