1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 // MARKER(update_precomp.py): autogen include statement, do not remove 23 #include "precompiled_ucb.hxx" 24 25 #include <SerfRequestProcessor.hxx> 26 #include <SerfRequestProcessorImpl.hxx> 27 #include <SerfRequestProcessorImplFac.hxx> 28 #include <SerfCallbacks.hxx> 29 #include <SerfSession.hxx> 30 31 #include <apr_strings.h> 32 33 namespace http_dav_ucp 34 { 35 36 SerfRequestProcessor::SerfRequestProcessor( SerfSession& rSerfSession, 37 const rtl::OUString & inPath, 38 const bool bUseChunkedEncoding ) 39 : mrSerfSession( rSerfSession ) 40 , mPathStr( 0 ) 41 , mbUseChunkedEncoding( bUseChunkedEncoding ) 42 , mDestPathStr( 0 ) 43 , mContentType( 0 ) 44 , mReferer( 0 ) 45 , mpProcImpl( 0 ) 46 , mbProcessingDone( false ) 47 , mpDAVException() 48 , mnHTTPStatusCode( SC_NONE ) 49 , mHTTPStatusCodeText() 50 , mRedirectLocation() 51 , mnSuccessfulCredentialAttempts( 0 ) 52 , mbInputOfCredentialsAborted( false ) 53 , mbSetupSerfRequestCalled( false ) 54 , mbAcceptSerfResponseCalled( false ) 55 , mbHandleSerfResponseCalled( false ) 56 { 57 mPathStr = apr_pstrdup( mrSerfSession.getAprPool(), 58 rtl::OUStringToOString( inPath, RTL_TEXTENCODING_UTF8 ) ); 59 } 60 61 SerfRequestProcessor::~SerfRequestProcessor() 62 { 63 delete mpProcImpl; 64 delete mpDAVException; 65 } 66 67 void SerfRequestProcessor::prepareProcessor() 68 { 69 delete mpDAVException; 70 mpDAVException = 0; 71 mnHTTPStatusCode = SC_NONE; 72 mHTTPStatusCodeText = rtl::OUString(); 73 mRedirectLocation = rtl::OUString(); 74 75 mnSuccessfulCredentialAttempts = 0; 76 mbInputOfCredentialsAborted = false; 77 mbSetupSerfRequestCalled = false; 78 mbAcceptSerfResponseCalled = false; 79 mbHandleSerfResponseCalled = false; 80 } 81 82 // PROPFIND - allprop & named 83 bool SerfRequestProcessor::processPropFind( const Depth inDepth, 84 const std::vector< ::rtl::OUString > & inPropNames, 85 std::vector< DAVResource > & ioResources, 86 apr_status_t& outSerfStatus ) 87 { 88 mpProcImpl = createPropFindReqProcImpl( mPathStr, 89 inDepth, 90 inPropNames, 91 ioResources ); 92 outSerfStatus = runProcessor(); 93 94 return outSerfStatus == APR_SUCCESS; 95 } 96 97 // PROPFIND - property names 98 bool SerfRequestProcessor::processPropFind( const Depth inDepth, 99 std::vector< DAVResourceInfo > & ioResInfo, 100 apr_status_t& outSerfStatus ) 101 { 102 mpProcImpl = createPropFindReqProcImpl( mPathStr, 103 inDepth, 104 ioResInfo ); 105 outSerfStatus = runProcessor(); 106 107 return outSerfStatus == APR_SUCCESS; 108 } 109 110 // PROPPATCH 111 bool SerfRequestProcessor::processPropPatch( const std::vector< ProppatchValue > & inProperties, 112 apr_status_t& outSerfStatus ) 113 { 114 mpProcImpl = createPropPatchReqProcImpl( mPathStr, 115 inProperties ); 116 outSerfStatus = runProcessor(); 117 118 return outSerfStatus == APR_SUCCESS; 119 } 120 121 // GET 122 bool SerfRequestProcessor::processGet( const com::sun::star::uno::Reference< SerfInputStream >& xioInStrm, 123 apr_status_t& outSerfStatus ) 124 { 125 mpProcImpl = createGetReqProcImpl( mPathStr, 126 xioInStrm ); 127 outSerfStatus = runProcessor(); 128 129 return outSerfStatus == APR_SUCCESS; 130 } 131 132 // GET inclusive header fields 133 bool SerfRequestProcessor::processGet( const com::sun::star::uno::Reference< SerfInputStream >& xioInStrm, 134 const std::vector< ::rtl::OUString > & inHeaderNames, 135 DAVResource & ioResource, 136 apr_status_t& outSerfStatus ) 137 { 138 mpProcImpl = createGetReqProcImpl( mPathStr, 139 xioInStrm, 140 inHeaderNames, 141 ioResource ); 142 outSerfStatus = runProcessor(); 143 144 return outSerfStatus == APR_SUCCESS; 145 } 146 147 // GET 148 bool SerfRequestProcessor::processGet( const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xioOutStrm, 149 apr_status_t& outSerfStatus ) 150 { 151 mpProcImpl = createGetReqProcImpl( mPathStr, 152 xioOutStrm ); 153 outSerfStatus = runProcessor(); 154 155 return outSerfStatus == APR_SUCCESS; 156 } 157 158 // GET inclusive header fields 159 bool SerfRequestProcessor::processGet( const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xioOutStrm, 160 const std::vector< ::rtl::OUString > & inHeaderNames, 161 DAVResource & ioResource, 162 apr_status_t& outSerfStatus ) 163 { 164 mpProcImpl = createGetReqProcImpl( mPathStr, 165 xioOutStrm, 166 inHeaderNames, 167 ioResource ); 168 outSerfStatus = runProcessor(); 169 170 return outSerfStatus == APR_SUCCESS; 171 } 172 173 // HEAD 174 bool SerfRequestProcessor::processHead( const std::vector< ::rtl::OUString > & inHeaderNames, 175 DAVResource & ioResource, 176 apr_status_t& outSerfStatus ) 177 { 178 mpProcImpl = createHeadReqProcImpl( mPathStr, 179 inHeaderNames, 180 ioResource ); 181 outSerfStatus = runProcessor(); 182 183 return outSerfStatus == APR_SUCCESS; 184 } 185 186 // PUT 187 bool SerfRequestProcessor::processPut( const char* inData, 188 apr_size_t inDataLen, 189 apr_status_t& outSerfStatus ) 190 { 191 mpProcImpl = createPutReqProcImpl( mPathStr, 192 inData, 193 inDataLen ); 194 outSerfStatus = runProcessor(); 195 196 return outSerfStatus == APR_SUCCESS; 197 } 198 199 // POST 200 bool SerfRequestProcessor::processPost( const char* inData, 201 apr_size_t inDataLen, 202 const rtl::OUString & inContentType, 203 const rtl::OUString & inReferer, 204 const com::sun::star::uno::Reference< SerfInputStream >& xioInStrm, 205 apr_status_t& outSerfStatus ) 206 { 207 mContentType = apr_pstrdup( mrSerfSession.getAprPool(), 208 rtl::OUStringToOString( inContentType, RTL_TEXTENCODING_UTF8 ) ); 209 mReferer = apr_pstrdup( mrSerfSession.getAprPool(), 210 rtl::OUStringToOString( inReferer, RTL_TEXTENCODING_UTF8 ) ); 211 mpProcImpl = createPostReqProcImpl( mPathStr, 212 inData, 213 inDataLen, 214 mContentType, 215 mReferer, 216 xioInStrm ); 217 outSerfStatus = runProcessor(); 218 219 return outSerfStatus == APR_SUCCESS; 220 } 221 222 // POST 223 bool SerfRequestProcessor::processPost( const char* inData, 224 apr_size_t inDataLen, 225 const rtl::OUString & inContentType, 226 const rtl::OUString & inReferer, 227 const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xioOutStrm, 228 apr_status_t& outSerfStatus ) 229 { 230 mContentType = apr_pstrdup( mrSerfSession.getAprPool(), 231 rtl::OUStringToOString( inContentType, RTL_TEXTENCODING_UTF8 ) ); 232 mReferer = apr_pstrdup( mrSerfSession.getAprPool(), 233 rtl::OUStringToOString( inReferer, RTL_TEXTENCODING_UTF8 ) ); 234 mpProcImpl = createPostReqProcImpl( mPathStr, 235 inData, 236 inDataLen, 237 mContentType, 238 mReferer, 239 xioOutStrm ); 240 outSerfStatus = runProcessor(); 241 242 return outSerfStatus == APR_SUCCESS; 243 } 244 245 // DELETE 246 bool SerfRequestProcessor::processDelete( apr_status_t& outSerfStatus ) 247 { 248 mpProcImpl = createDeleteReqProcImpl( mPathStr ); 249 outSerfStatus = runProcessor(); 250 251 return outSerfStatus == APR_SUCCESS; 252 } 253 254 // MKCOL 255 bool SerfRequestProcessor::processMkCol( apr_status_t& outSerfStatus ) 256 { 257 mpProcImpl = createMkColReqProcImpl( mPathStr ); 258 outSerfStatus = runProcessor(); 259 260 return outSerfStatus == APR_SUCCESS; 261 } 262 263 // COPY 264 bool SerfRequestProcessor::processCopy( const rtl::OUString & inDestinationPath, 265 const bool inOverwrite, 266 apr_status_t& outSerfStatus ) 267 { 268 mDestPathStr = apr_pstrdup( mrSerfSession.getAprPool(), 269 rtl::OUStringToOString( inDestinationPath, RTL_TEXTENCODING_UTF8 ) ); 270 mpProcImpl = createCopyReqProcImpl( mPathStr, 271 mDestPathStr, 272 inOverwrite ); 273 outSerfStatus = runProcessor(); 274 275 return outSerfStatus == APR_SUCCESS; 276 } 277 278 // MOVE 279 bool SerfRequestProcessor::processMove( const rtl::OUString & inDestinationPath, 280 const bool inOverwrite, 281 apr_status_t& outSerfStatus ) 282 { 283 mDestPathStr = apr_pstrdup( mrSerfSession.getAprPool(), 284 rtl::OUStringToOString( inDestinationPath, RTL_TEXTENCODING_UTF8 ) ); 285 mpProcImpl = createMoveReqProcImpl( mPathStr, 286 mDestPathStr, 287 inOverwrite ); 288 outSerfStatus = runProcessor(); 289 290 return outSerfStatus == APR_SUCCESS; 291 } 292 293 apr_status_t SerfRequestProcessor::runProcessor() 294 { 295 prepareProcessor(); 296 297 // activate chunked encoding, if requested 298 if ( mbUseChunkedEncoding ) 299 { 300 mpProcImpl->activateChunkedEncoding(); 301 } 302 303 // create serf request 304 serf_connection_request_create( mrSerfSession.getSerfConnection(), 305 Serf_SetupRequest, 306 this ); 307 308 // perform serf request 309 mbProcessingDone = false; 310 apr_status_t status = APR_SUCCESS; 311 serf_context_t* pSerfContext = mrSerfSession.getSerfContext(); 312 apr_pool_t* pAprPool = mrSerfSession.getAprPool(); 313 while ( true ) 314 { 315 status = serf_context_run( pSerfContext, 316 SERF_DURATION_FOREVER, 317 pAprPool ); 318 if ( APR_STATUS_IS_TIMEUP( status ) ) 319 { 320 continue; 321 } 322 if ( status != APR_SUCCESS ) 323 { 324 break; 325 } 326 if ( mbProcessingDone ) 327 { 328 break; 329 } 330 } 331 332 postprocessProcessor( status ); 333 334 return status; 335 } 336 337 void SerfRequestProcessor::postprocessProcessor( const apr_status_t inStatus ) 338 { 339 if ( inStatus == APR_SUCCESS ) 340 { 341 return; 342 } 343 344 switch ( inStatus ) 345 { 346 case APR_EGENERAL: 347 case SERF_ERROR_AUTHN_FAILED: 348 // general error; <mnHTTPStatusCode> provides more information 349 { 350 switch ( mnHTTPStatusCode ) 351 { 352 case SC_NONE: 353 if ( !mbSetupSerfRequestCalled ) 354 { 355 mpDAVException = new DAVException( DAVException::DAV_HTTP_LOOKUP, 356 SerfUri::makeConnectionEndPointString( mrSerfSession.getHostName(), 357 mrSerfSession.getPort() ) ); 358 } 359 else if ( mbInputOfCredentialsAborted ) 360 { 361 mpDAVException = new DAVException( DAVException::DAV_HTTP_NOAUTH, 362 SerfUri::makeConnectionEndPointString( mrSerfSession.getHostName(), 363 mrSerfSession.getPort() ) ); 364 } 365 else 366 { 367 mpDAVException = new DAVException( DAVException::DAV_HTTP_ERROR, 368 mHTTPStatusCodeText, 369 mnHTTPStatusCode ); 370 } 371 break; 372 case SC_MOVED_PERMANENTLY: 373 case SC_MOVED_TEMPORARILY: 374 case SC_SEE_OTHER: 375 case SC_TEMPORARY_REDIRECT: 376 mpDAVException = new DAVException( DAVException::DAV_HTTP_REDIRECT, 377 mRedirectLocation ); 378 break; 379 default: 380 mpDAVException = new DAVException( DAVException::DAV_HTTP_ERROR, 381 mHTTPStatusCodeText, 382 mnHTTPStatusCode ); 383 break; 384 } 385 } 386 break; 387 388 default: 389 mpDAVException = new DAVException( DAVException::DAV_HTTP_ERROR ); 390 break; 391 } 392 393 } 394 395 apr_status_t SerfRequestProcessor::provideSerfCredentials( char ** outUsername, 396 char ** outPassword, 397 serf_request_t * inRequest, 398 int inCode, 399 const char *inAuthProtocol, 400 const char *inRealm, 401 apr_pool_t *inAprPool ) 402 { 403 // as each successful provided credentials are tried twice - see below - the 404 // number of real attempts is half of the value of <mnSuccessfulCredentialAttempts> 405 if ( (mnSuccessfulCredentialAttempts / 2) >= 5 || 406 mbInputOfCredentialsAborted ) 407 { 408 mbInputOfCredentialsAborted = true; 409 return SERF_ERROR_AUTHN_FAILED; 410 } 411 412 // because serf keeps credentials only for a connection in case of digest authentication 413 // we give each successful provided credentials a second try in order to workaround the 414 // situation that the connection for which the credentials have been provided has been closed 415 // before the provided credentials could be applied for the request. 416 apr_status_t status = mrSerfSession.provideSerfCredentials( (mnSuccessfulCredentialAttempts % 2) == 1, 417 outUsername, 418 outPassword, 419 inRequest, 420 inCode, 421 inAuthProtocol, 422 inRealm, 423 inAprPool ); 424 if ( status != APR_SUCCESS ) 425 { 426 mbInputOfCredentialsAborted = true; 427 } 428 else 429 { 430 ++mnSuccessfulCredentialAttempts; 431 } 432 433 return status; 434 } 435 436 apr_status_t SerfRequestProcessor::setupSerfRequest( serf_request_t * inSerfRequest, 437 serf_bucket_t ** outSerfRequestBucket, 438 serf_response_acceptor_t * outSerfResponseAcceptor, 439 void ** outSerfResponseAcceptorBaton, 440 serf_response_handler_t * outSerfResponseHandler, 441 void ** outSerfResponseHandlerBaton, 442 apr_pool_t * /*inAprPool*/ ) 443 { 444 mbSetupSerfRequestCalled = true; 445 *outSerfRequestBucket = mpProcImpl->createSerfRequestBucket( inSerfRequest ); 446 447 // apply callbacks for accepting response and handling response 448 *outSerfResponseAcceptor = Serf_AcceptResponse; 449 *outSerfResponseAcceptorBaton = this; 450 *outSerfResponseHandler = Serf_HandleResponse; 451 *outSerfResponseHandlerBaton = this; 452 453 return APR_SUCCESS; 454 } 455 456 serf_bucket_t* SerfRequestProcessor::acceptSerfResponse( serf_request_t * inSerfRequest, 457 serf_bucket_t * inSerfStreamBucket, 458 apr_pool_t * inAprPool ) 459 { 460 mbAcceptSerfResponseCalled = true; 461 return mrSerfSession.acceptSerfResponse( inSerfRequest, 462 inSerfStreamBucket, 463 inAprPool ); 464 } 465 466 apr_status_t SerfRequestProcessor::handleSerfResponse( serf_request_t * inSerfRequest, 467 serf_bucket_t * inSerfResponseBucket, 468 apr_pool_t * inAprPool ) 469 { 470 mbHandleSerfResponseCalled = true; 471 472 // some general response handling and error handling 473 { 474 if ( !inSerfResponseBucket ) 475 { 476 /* A NULL response can come back if the request failed completely */ 477 mbProcessingDone = true; 478 return APR_EGENERAL; 479 } 480 481 serf_status_line sl; 482 apr_status_t status = serf_bucket_response_status( inSerfResponseBucket, &sl ); 483 if ( status ) 484 { 485 mbProcessingDone = false; // allow another try in order to get a response 486 return status; 487 } 488 // TODO - check, if response status code handling is correct 489 mnHTTPStatusCode = ( sl.version != 0 && sl.code >= 0 ) 490 ? static_cast< sal_uInt16 >( sl.code ) 491 : SC_NONE; 492 if ( sl.reason ) 493 { 494 mHTTPStatusCodeText = ::rtl::OUString::createFromAscii( sl.reason ); 495 } 496 if ( ( sl.version == 0 || sl.code < 0 ) || 497 mnHTTPStatusCode >= 300 ) 498 { 499 if ( mnHTTPStatusCode == 301 || 500 mnHTTPStatusCode == 302 || 501 mnHTTPStatusCode == 303 || 502 mnHTTPStatusCode == 307 ) 503 { 504 // new location for certain redirections 505 serf_bucket_t *headers = serf_bucket_response_get_headers( inSerfResponseBucket ); 506 const char* location = serf_bucket_headers_get( headers, "Location" ); 507 if ( location ) 508 { 509 mRedirectLocation = rtl::OUString::createFromAscii( location ); 510 } 511 mbProcessingDone = true; 512 return APR_EGENERAL; 513 } 514 else if ( mrSerfSession.isHeadRequestInProgress() && 515 ( mnHTTPStatusCode == 401 || mnHTTPStatusCode == 407 ) ) 516 { 517 // keep going as authentication is not required on HEAD request. 518 // the response already contains header fields. 519 } 520 else 521 { 522 mbProcessingDone = true; 523 return APR_EGENERAL; 524 } 525 } 526 } 527 528 // request specific processing of the response bucket 529 apr_status_t status = APR_SUCCESS; 530 mbProcessingDone = mpProcImpl->processSerfResponseBucket( inSerfRequest, 531 inSerfResponseBucket, 532 inAprPool, 533 status ); 534 535 return status; 536 } 537 538 } // namespace http_dav_ucp 539 540