bump product version to 5.0.4.1
[LibreOffice.git] / ucb / source / ucp / webdav / SerfRequestProcessor.cxx
blob06088d20a99f5b67ec8ad50bd0c62b4392470c86
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
22 #include "AprEnv.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 )
47 , mPathStr( 0 )
48 , mbUseChunkedEncoding( bUseChunkedEncoding )
49 , mDestPathStr( 0 )
50 , mContentType( 0 )
51 , mReferer( 0 )
52 , mpProcImpl( 0 )
53 , mbProcessingDone( false )
54 , mpDAVException()
55 , mnHTTPStatusCode( SC_NONE )
56 , mHTTPStatusCodeText()
57 , mRedirectLocation()
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()
70 delete mpProcImpl;
71 delete mpDAVException;
74 void SerfRequestProcessor::prepareProcessor()
76 delete mpDAVException;
77 mpDAVException = 0;
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,
97 inDepth,
98 inPropNames,
99 ioResources );
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,
112 inDepth,
113 ioResInfo );
114 outSerfStatus = runProcessor();
116 return outSerfStatus == APR_SUCCESS;
119 // PROPPATCH
120 bool SerfRequestProcessor::processPropPatch( const std::vector< ProppatchValue > & inProperties,
121 apr_status_t& outSerfStatus )
123 mpProcImpl = new SerfPropPatchReqProcImpl( mPathStr,
124 mrSerfSession.getRequestEnvironment().m_aRequestHeaders,
125 inProperties );
126 outSerfStatus = runProcessor();
128 return outSerfStatus == APR_SUCCESS;
131 // GET
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,
137 xioInStrm );
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,
151 xioInStrm,
152 inHeaderNames,
153 ioResource );
154 outSerfStatus = runProcessor();
156 return outSerfStatus == APR_SUCCESS;
159 // GET
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,
165 xioOutStrm );
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,
179 xioOutStrm,
180 inHeaderNames,
181 ioResource );
182 outSerfStatus = runProcessor();
184 return outSerfStatus == APR_SUCCESS;
187 // HEAD
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,
194 inHeaderNames,
195 ioResource );
196 outSerfStatus = runProcessor();
198 return outSerfStatus == APR_SUCCESS;
201 // PUT
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,
213 inData,
214 inDataLen,
215 sToken );
216 outSerfStatus = runProcessor();
218 return outSerfStatus == APR_SUCCESS;
221 // POST
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,
235 inData,
236 inDataLen,
237 mContentType,
238 mReferer,
239 xioInStrm );
240 outSerfStatus = runProcessor();
242 return outSerfStatus == APR_SUCCESS;
245 // POST
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,
259 inData,
260 inDataLen,
261 mContentType,
262 mReferer,
263 xioOutStrm );
264 outSerfStatus = runProcessor();
266 return outSerfStatus == APR_SUCCESS;
269 // DELETE
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;
279 // MKCOL
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;
289 // COPY
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,
298 mDestPathStr,
299 inOverwrite );
300 outSerfStatus = runProcessor();
302 return outSerfStatus == APR_SUCCESS;
305 // MOVE
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,
314 mDestPathStr,
315 inOverwrite );
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,
326 mrSerfSession,
327 rLock,
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,
344 sToken );
346 return runProcessor() == APR_SUCCESS;
349 apr_status_t SerfRequestProcessor::runProcessor()
351 prepareProcessor();
353 // activate chunked encoding, if requested
354 if ( mbUseChunkedEncoding )
356 mpProcImpl->activateChunkedEncoding();
359 // create serf request
360 serf_connection_request_create( mrSerfSession.getSerfConnection(),
361 Serf_SetupRequest,
362 this );
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();
369 while ( true )
371 status = serf_context_run( pSerfContext,
372 SERF_DURATION_FOREVER,
373 pAprPool );
374 if ( APR_STATUS_IS_TIMEUP( status ) )
376 continue;
378 if ( status != APR_SUCCESS )
380 break;
382 if ( mbProcessingDone )
384 break;
388 postprocessProcessor( status );
390 return status;
393 void SerfRequestProcessor::postprocessProcessor( const apr_status_t inStatus )
395 if ( inStatus == APR_SUCCESS )
397 return;
400 switch ( inStatus )
402 case APR_EGENERAL:
403 case SERF_ERROR_AUTHN_FAILED:
404 // general error; <mnHTTPStatusCode> provides more information
406 switch ( mnHTTPStatusCode )
408 case SC_NONE:
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() ) );
421 else
423 mpDAVException = new DAVException( DAVException::DAV_HTTP_ERROR,
424 mHTTPStatusCodeText,
425 mnHTTPStatusCode );
427 break;
428 case SC_MOVED_PERMANENTLY:
429 case SC_MOVED_TEMPORARILY:
430 case SC_SEE_OTHER:
431 case SC_TEMPORARY_REDIRECT:
432 mpDAVException = new DAVException( DAVException::DAV_HTTP_REDIRECT,
433 mRedirectLocation );
434 break;
435 default:
436 mpDAVException = new DAVException( DAVException::DAV_HTTP_ERROR,
437 mHTTPStatusCodeText,
438 mnHTTPStatusCode );
439 break;
442 break;
444 default:
445 mpDAVException = new DAVException( DAVException::DAV_HTTP_ERROR );
446 break;
451 apr_status_t SerfRequestProcessor::provideSerfCredentials( char ** outUsername,
452 char ** outPassword,
453 serf_request_t * inRequest,
454 int inCode,
455 const char *inAuthProtocol,
456 const char *inRealm,
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,
473 outUsername,
474 outPassword,
475 inRequest,
476 inCode,
477 inAuthProtocol,
478 inRealm,
479 inAprPool );
480 if ( status != APR_SUCCESS )
482 mbInputOfCredentialsAborted = true;
484 else
486 ++mnSuccessfulCredentialAttempts;
489 return status;
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;
509 return APR_SUCCESS;
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,
518 inSerfStreamBucket,
519 inAprPool );
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;
534 return APR_EGENERAL;
537 serf_status_line sl;
538 apr_status_t status = serf_bucket_response_status( inSerfResponseBucket, &sl );
539 if ( status )
541 mbProcessingDone = false; // allow another try in order to get a response
542 return status;
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 )
547 : SC_NONE;
548 if ( sl.reason )
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" );
563 if ( location )
565 mRedirectLocation = OUString::createFromAscii( location );
567 mbProcessingDone = true;
568 return APR_EGENERAL;
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.
576 else
578 mbProcessingDone = true;
579 return APR_EGENERAL;
584 // request specific processing of the response bucket
585 apr_status_t status = APR_SUCCESS;
586 mbProcessingDone = mpProcImpl->processSerfResponseBucket( inSerfRequest,
587 inSerfResponseBucket,
588 inAprPool,
589 status );
591 return status;
594 } // namespace http_dav_ucp
596 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */