Version 4.0.2.1, tag libreoffice-4.0.2.1
[LibreOffice.git] / ucb / source / ucp / webdav / SerfRequestProcessor.cxx
blobf73766f6df0be1802f3ca5306d4c2d9c2bfcea3d
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>
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 )
35 , mPathStr( 0 )
36 , mbUseChunkedEncoding( bUseChunkedEncoding )
37 , mDestPathStr( 0 )
38 , mContentType( 0 )
39 , mReferer( 0 )
40 , mpProcImpl( 0 )
41 , mbProcessingDone( false )
42 , mpDAVException()
43 , mnHTTPStatusCode( SC_NONE )
44 , mHTTPStatusCodeText()
45 , mRedirectLocation()
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()
58 delete mpProcImpl;
59 delete mpDAVException;
62 void SerfRequestProcessor::prepareProcessor()
64 delete mpDAVException;
65 mpDAVException = 0;
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,
85 inDepth,
86 inPropNames,
87 ioResources );
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,
100 inDepth,
101 ioResInfo );
102 outSerfStatus = runProcessor();
104 return outSerfStatus == APR_SUCCESS;
107 // PROPPATCH
108 bool SerfRequestProcessor::processPropPatch( const std::vector< ProppatchValue > & inProperties,
109 apr_status_t& outSerfStatus )
111 mpProcImpl = createPropPatchReqProcImpl( mPathStr,
112 mrSerfSession.getRequestEnvironment().m_aRequestHeaders,
113 inProperties );
114 outSerfStatus = runProcessor();
116 return outSerfStatus == APR_SUCCESS;
119 // GET
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,
125 xioInStrm );
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,
139 xioInStrm,
140 inHeaderNames,
141 ioResource );
142 outSerfStatus = runProcessor();
144 return outSerfStatus == APR_SUCCESS;
147 // GET
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,
153 xioOutStrm );
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,
167 xioOutStrm,
168 inHeaderNames,
169 ioResource );
170 outSerfStatus = runProcessor();
172 return outSerfStatus == APR_SUCCESS;
175 // HEAD
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,
182 inHeaderNames,
183 ioResource );
184 outSerfStatus = runProcessor();
186 return outSerfStatus == APR_SUCCESS;
189 // PUT
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,
196 inData,
197 inDataLen );
198 outSerfStatus = runProcessor();
200 return outSerfStatus == APR_SUCCESS;
203 // POST
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,
217 inData,
218 inDataLen,
219 mContentType,
220 mReferer,
221 xioInStrm );
222 outSerfStatus = runProcessor();
224 return outSerfStatus == APR_SUCCESS;
227 // POST
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,
241 inData,
242 inDataLen,
243 mContentType,
244 mReferer,
245 xioOutStrm );
246 outSerfStatus = runProcessor();
248 return outSerfStatus == APR_SUCCESS;
251 // DELETE
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;
261 // MKCOL
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;
271 // COPY
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,
280 mDestPathStr,
281 inOverwrite );
282 outSerfStatus = runProcessor();
284 return outSerfStatus == APR_SUCCESS;
287 // MOVE
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,
296 mDestPathStr,
297 inOverwrite );
298 outSerfStatus = runProcessor();
300 return outSerfStatus == APR_SUCCESS;
303 apr_status_t SerfRequestProcessor::runProcessor()
305 prepareProcessor();
307 // activate chunked encoding, if requested
308 if ( mbUseChunkedEncoding )
310 mpProcImpl->activateChunkedEncoding();
313 // create serf request
314 serf_connection_request_create( mrSerfSession.getSerfConnection(),
315 Serf_SetupRequest,
316 this );
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();
323 while ( true )
325 status = serf_context_run( pSerfContext,
326 SERF_DURATION_FOREVER,
327 pAprPool );
328 if ( APR_STATUS_IS_TIMEUP( status ) )
330 continue;
332 if ( status != APR_SUCCESS )
334 break;
336 if ( mbProcessingDone )
338 break;
342 postprocessProcessor( status );
344 return status;
347 void SerfRequestProcessor::postprocessProcessor( const apr_status_t inStatus )
349 if ( inStatus == APR_SUCCESS )
351 return;
354 switch ( inStatus )
356 case APR_EGENERAL:
357 case SERF_ERROR_AUTHN_FAILED:
358 // general error; <mnHTTPStatusCode> provides more information
360 switch ( mnHTTPStatusCode )
362 case SC_NONE:
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() ) );
375 else
377 mpDAVException = new DAVException( DAVException::DAV_HTTP_ERROR,
378 mHTTPStatusCodeText,
379 mnHTTPStatusCode );
381 break;
382 case SC_MOVED_PERMANENTLY:
383 case SC_MOVED_TEMPORARILY:
384 case SC_SEE_OTHER:
385 case SC_TEMPORARY_REDIRECT:
386 mpDAVException = new DAVException( DAVException::DAV_HTTP_REDIRECT,
387 mRedirectLocation );
388 break;
389 default:
390 mpDAVException = new DAVException( DAVException::DAV_HTTP_ERROR,
391 mHTTPStatusCodeText,
392 mnHTTPStatusCode );
393 break;
396 break;
398 default:
399 mpDAVException = new DAVException( DAVException::DAV_HTTP_ERROR );
400 break;
405 apr_status_t SerfRequestProcessor::provideSerfCredentials( char ** outUsername,
406 char ** outPassword,
407 serf_request_t * inRequest,
408 int inCode,
409 const char *inAuthProtocol,
410 const char *inRealm,
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,
427 outUsername,
428 outPassword,
429 inRequest,
430 inCode,
431 inAuthProtocol,
432 inRealm,
433 inAprPool );
434 if ( status != APR_SUCCESS )
436 mbInputOfCredentialsAborted = true;
438 else
440 ++mnSuccessfulCredentialAttempts;
443 return status;
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;
463 return APR_SUCCESS;
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,
472 inSerfStreamBucket,
473 inAprPool );
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;
488 return APR_EGENERAL;
491 serf_status_line sl;
492 apr_status_t status = serf_bucket_response_status( inSerfResponseBucket, &sl );
493 if ( status )
495 mbProcessingDone = false; // allow another try in order to get a response
496 return status;
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 )
501 : SC_NONE;
502 if ( sl.reason )
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" );
517 if ( location )
519 mRedirectLocation = rtl::OUString::createFromAscii( location );
521 mbProcessingDone = true;
522 return APR_EGENERAL;
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.
530 else
532 mbProcessingDone = true;
533 return APR_EGENERAL;
538 // request specific processing of the response bucket
539 apr_status_t status = APR_SUCCESS;
540 mbProcessingDone = mpProcImpl->processSerfResponseBucket( inSerfRequest,
541 inSerfResponseBucket,
542 inAprPool,
543 status );
545 return status;
548 } // namespace http_dav_ucp
550 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */