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 mrSerfSession.getRequestEnvironment().m_aRequestHeaders, 90 inDepth, 91 inPropNames, 92 ioResources ); 93 outSerfStatus = runProcessor(); 94 95 return outSerfStatus == APR_SUCCESS; 96 } 97 98 // PROPFIND - property names 99 bool SerfRequestProcessor::processPropFind( const Depth inDepth, 100 std::vector< DAVResourceInfo > & ioResInfo, 101 apr_status_t& outSerfStatus ) 102 { 103 mpProcImpl = createPropFindReqProcImpl( mPathStr, 104 mrSerfSession.getRequestEnvironment().m_aRequestHeaders, 105 inDepth, 106 ioResInfo ); 107 outSerfStatus = runProcessor(); 108 109 return outSerfStatus == APR_SUCCESS; 110 } 111 112 // PROPPATCH 113 bool SerfRequestProcessor::processPropPatch( const std::vector< ProppatchValue > & inProperties, 114 apr_status_t& outSerfStatus ) 115 { 116 mpProcImpl = createPropPatchReqProcImpl( mPathStr, 117 mrSerfSession.getRequestEnvironment().m_aRequestHeaders, 118 inProperties ); 119 outSerfStatus = runProcessor(); 120 121 return outSerfStatus == APR_SUCCESS; 122 } 123 124 // GET 125 bool SerfRequestProcessor::processGet( const com::sun::star::uno::Reference< SerfInputStream >& xioInStrm, 126 apr_status_t& outSerfStatus ) 127 { 128 mpProcImpl = createGetReqProcImpl( mPathStr, 129 mrSerfSession.getRequestEnvironment().m_aRequestHeaders, 130 xioInStrm ); 131 outSerfStatus = runProcessor(); 132 133 return outSerfStatus == APR_SUCCESS; 134 } 135 136 // GET inclusive header fields 137 bool SerfRequestProcessor::processGet( const com::sun::star::uno::Reference< SerfInputStream >& xioInStrm, 138 const std::vector< ::rtl::OUString > & inHeaderNames, 139 DAVResource & ioResource, 140 apr_status_t& outSerfStatus ) 141 { 142 mpProcImpl = createGetReqProcImpl( mPathStr, 143 mrSerfSession.getRequestEnvironment().m_aRequestHeaders, 144 xioInStrm, 145 inHeaderNames, 146 ioResource ); 147 outSerfStatus = runProcessor(); 148 149 return outSerfStatus == APR_SUCCESS; 150 } 151 152 // GET 153 bool SerfRequestProcessor::processGet( const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xioOutStrm, 154 apr_status_t& outSerfStatus ) 155 { 156 mpProcImpl = createGetReqProcImpl( mPathStr, 157 mrSerfSession.getRequestEnvironment().m_aRequestHeaders, 158 xioOutStrm ); 159 outSerfStatus = runProcessor(); 160 161 return outSerfStatus == APR_SUCCESS; 162 } 163 164 // GET inclusive header fields 165 bool SerfRequestProcessor::processGet( const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xioOutStrm, 166 const std::vector< ::rtl::OUString > & inHeaderNames, 167 DAVResource & ioResource, 168 apr_status_t& outSerfStatus ) 169 { 170 mpProcImpl = createGetReqProcImpl( mPathStr, 171 mrSerfSession.getRequestEnvironment().m_aRequestHeaders, 172 xioOutStrm, 173 inHeaderNames, 174 ioResource ); 175 outSerfStatus = runProcessor(); 176 177 return outSerfStatus == APR_SUCCESS; 178 } 179 180 // HEAD 181 bool SerfRequestProcessor::processHead( const std::vector< ::rtl::OUString > & inHeaderNames, 182 DAVResource & ioResource, 183 apr_status_t& outSerfStatus ) 184 { 185 mpProcImpl = createHeadReqProcImpl( mPathStr, 186 mrSerfSession.getRequestEnvironment().m_aRequestHeaders, 187 inHeaderNames, 188 ioResource ); 189 outSerfStatus = runProcessor(); 190 191 return outSerfStatus == APR_SUCCESS; 192 } 193 194 // PUT 195 bool SerfRequestProcessor::processPut( const char* inData, 196 apr_size_t inDataLen, 197 apr_status_t& outSerfStatus ) 198 { 199 mpProcImpl = createPutReqProcImpl( mPathStr, 200 mrSerfSession.getRequestEnvironment().m_aRequestHeaders, 201 inData, 202 inDataLen ); 203 outSerfStatus = runProcessor(); 204 205 return outSerfStatus == APR_SUCCESS; 206 } 207 208 // POST 209 bool SerfRequestProcessor::processPost( const char* inData, 210 apr_size_t inDataLen, 211 const rtl::OUString & inContentType, 212 const rtl::OUString & inReferer, 213 const com::sun::star::uno::Reference< SerfInputStream >& xioInStrm, 214 apr_status_t& outSerfStatus ) 215 { 216 mContentType = apr_pstrdup( mrSerfSession.getAprPool(), 217 rtl::OUStringToOString( inContentType, RTL_TEXTENCODING_UTF8 ) ); 218 mReferer = apr_pstrdup( mrSerfSession.getAprPool(), 219 rtl::OUStringToOString( inReferer, RTL_TEXTENCODING_UTF8 ) ); 220 mpProcImpl = createPostReqProcImpl( mPathStr, 221 mrSerfSession.getRequestEnvironment().m_aRequestHeaders, 222 inData, 223 inDataLen, 224 mContentType, 225 mReferer, 226 xioInStrm ); 227 outSerfStatus = runProcessor(); 228 229 return outSerfStatus == APR_SUCCESS; 230 } 231 232 // POST 233 bool SerfRequestProcessor::processPost( const char* inData, 234 apr_size_t inDataLen, 235 const rtl::OUString & inContentType, 236 const rtl::OUString & inReferer, 237 const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xioOutStrm, 238 apr_status_t& outSerfStatus ) 239 { 240 mContentType = apr_pstrdup( mrSerfSession.getAprPool(), 241 rtl::OUStringToOString( inContentType, RTL_TEXTENCODING_UTF8 ) ); 242 mReferer = apr_pstrdup( mrSerfSession.getAprPool(), 243 rtl::OUStringToOString( inReferer, RTL_TEXTENCODING_UTF8 ) ); 244 mpProcImpl = createPostReqProcImpl( mPathStr, 245 mrSerfSession.getRequestEnvironment().m_aRequestHeaders, 246 inData, 247 inDataLen, 248 mContentType, 249 mReferer, 250 xioOutStrm ); 251 outSerfStatus = runProcessor(); 252 253 return outSerfStatus == APR_SUCCESS; 254 } 255 256 // DELETE 257 bool SerfRequestProcessor::processDelete( apr_status_t& outSerfStatus ) 258 { 259 mpProcImpl = createDeleteReqProcImpl( mPathStr, 260 mrSerfSession.getRequestEnvironment().m_aRequestHeaders ); 261 outSerfStatus = runProcessor(); 262 263 return outSerfStatus == APR_SUCCESS; 264 } 265 266 // MKCOL 267 bool SerfRequestProcessor::processMkCol( apr_status_t& outSerfStatus ) 268 { 269 mpProcImpl = createMkColReqProcImpl( mPathStr, 270 mrSerfSession.getRequestEnvironment().m_aRequestHeaders ); 271 outSerfStatus = runProcessor(); 272 273 return outSerfStatus == APR_SUCCESS; 274 } 275 276 // COPY 277 bool SerfRequestProcessor::processCopy( const rtl::OUString & inDestinationPath, 278 const bool inOverwrite, 279 apr_status_t& outSerfStatus ) 280 { 281 mDestPathStr = apr_pstrdup( mrSerfSession.getAprPool(), 282 rtl::OUStringToOString( inDestinationPath, RTL_TEXTENCODING_UTF8 ) ); 283 mpProcImpl = createCopyReqProcImpl( mPathStr, 284 mrSerfSession.getRequestEnvironment().m_aRequestHeaders, 285 mDestPathStr, 286 inOverwrite ); 287 outSerfStatus = runProcessor(); 288 289 return outSerfStatus == APR_SUCCESS; 290 } 291 292 // MOVE 293 bool SerfRequestProcessor::processMove( const rtl::OUString & inDestinationPath, 294 const bool inOverwrite, 295 apr_status_t& outSerfStatus ) 296 { 297 mDestPathStr = apr_pstrdup( mrSerfSession.getAprPool(), 298 rtl::OUStringToOString( inDestinationPath, RTL_TEXTENCODING_UTF8 ) ); 299 mpProcImpl = createMoveReqProcImpl( mPathStr, 300 mrSerfSession.getRequestEnvironment().m_aRequestHeaders, 301 mDestPathStr, 302 inOverwrite ); 303 outSerfStatus = runProcessor(); 304 305 return outSerfStatus == APR_SUCCESS; 306 } 307 308 apr_status_t SerfRequestProcessor::runProcessor() 309 { 310 prepareProcessor(); 311 312 // activate chunked encoding, if requested 313 if ( mbUseChunkedEncoding ) 314 { 315 mpProcImpl->activateChunkedEncoding(); 316 } 317 318 // create serf request 319 serf_connection_request_create( mrSerfSession.getSerfConnection(), 320 Serf_SetupRequest, 321 this ); 322 323 // perform serf request 324 mbProcessingDone = false; 325 apr_status_t status = APR_SUCCESS; 326 serf_context_t* pSerfContext = mrSerfSession.getSerfContext(); 327 apr_pool_t* pAprPool = mrSerfSession.getAprPool(); 328 while ( true ) 329 { 330 status = serf_context_run( pSerfContext, 331 SERF_DURATION_FOREVER, 332 pAprPool ); 333 if ( APR_STATUS_IS_TIMEUP( status ) ) 334 { 335 continue; 336 } 337 if ( status != APR_SUCCESS ) 338 { 339 break; 340 } 341 if ( mbProcessingDone ) 342 { 343 break; 344 } 345 } 346 347 postprocessProcessor( status ); 348 349 return status; 350 } 351 352 void SerfRequestProcessor::postprocessProcessor( const apr_status_t inStatus ) 353 { 354 if ( inStatus == APR_SUCCESS ) 355 { 356 return; 357 } 358 359 switch ( inStatus ) 360 { 361 case APR_EGENERAL: 362 case SERF_ERROR_AUTHN_FAILED: 363 // general error; <mnHTTPStatusCode> provides more information 364 { 365 switch ( mnHTTPStatusCode ) 366 { 367 case SC_NONE: 368 if ( !mbSetupSerfRequestCalled ) 369 { 370 mpDAVException = new DAVException( DAVException::DAV_HTTP_LOOKUP, 371 SerfUri::makeConnectionEndPointString( mrSerfSession.getHostName(), 372 mrSerfSession.getPort() ) ); 373 } 374 else if ( mbInputOfCredentialsAborted ) 375 { 376 mpDAVException = new DAVException( DAVException::DAV_HTTP_NOAUTH, 377 SerfUri::makeConnectionEndPointString( mrSerfSession.getHostName(), 378 mrSerfSession.getPort() ) ); 379 } 380 else 381 { 382 mpDAVException = new DAVException( DAVException::DAV_HTTP_ERROR, 383 mHTTPStatusCodeText, 384 mnHTTPStatusCode ); 385 } 386 break; 387 case SC_MOVED_PERMANENTLY: 388 case SC_MOVED_TEMPORARILY: 389 case SC_SEE_OTHER: 390 case SC_TEMPORARY_REDIRECT: 391 mpDAVException = new DAVException( DAVException::DAV_HTTP_REDIRECT, 392 mRedirectLocation ); 393 break; 394 default: 395 mpDAVException = new DAVException( DAVException::DAV_HTTP_ERROR, 396 mHTTPStatusCodeText, 397 mnHTTPStatusCode ); 398 break; 399 } 400 } 401 break; 402 403 default: 404 mpDAVException = new DAVException( DAVException::DAV_HTTP_ERROR ); 405 break; 406 } 407 408 } 409 410 apr_status_t SerfRequestProcessor::provideSerfCredentials( char ** outUsername, 411 char ** outPassword, 412 serf_request_t * inRequest, 413 int inCode, 414 const char *inAuthProtocol, 415 const char *inRealm, 416 apr_pool_t *inAprPool ) 417 { 418 // as each successful provided credentials are tried twice - see below - the 419 // number of real attempts is half of the value of <mnSuccessfulCredentialAttempts> 420 if ( (mnSuccessfulCredentialAttempts / 2) >= 5 || 421 mbInputOfCredentialsAborted ) 422 { 423 mbInputOfCredentialsAborted = true; 424 return SERF_ERROR_AUTHN_FAILED; 425 } 426 427 // because serf keeps credentials only for a connection in case of digest authentication 428 // we give each successful provided credentials a second try in order to workaround the 429 // situation that the connection for which the credentials have been provided has been closed 430 // before the provided credentials could be applied for the request. 431 apr_status_t status = mrSerfSession.provideSerfCredentials( (mnSuccessfulCredentialAttempts % 2) == 1, 432 outUsername, 433 outPassword, 434 inRequest, 435 inCode, 436 inAuthProtocol, 437 inRealm, 438 inAprPool ); 439 if ( status != APR_SUCCESS ) 440 { 441 mbInputOfCredentialsAborted = true; 442 } 443 else 444 { 445 ++mnSuccessfulCredentialAttempts; 446 } 447 448 return status; 449 } 450 451 apr_status_t SerfRequestProcessor::setupSerfRequest( serf_request_t * inSerfRequest, 452 serf_bucket_t ** outSerfRequestBucket, 453 serf_response_acceptor_t * outSerfResponseAcceptor, 454 void ** outSerfResponseAcceptorBaton, 455 serf_response_handler_t * outSerfResponseHandler, 456 void ** outSerfResponseHandlerBaton, 457 apr_pool_t * /*inAprPool*/ ) 458 { 459 mbSetupSerfRequestCalled = true; 460 *outSerfRequestBucket = mpProcImpl->createSerfRequestBucket( inSerfRequest ); 461 462 // apply callbacks for accepting response and handling response 463 *outSerfResponseAcceptor = Serf_AcceptResponse; 464 *outSerfResponseAcceptorBaton = this; 465 *outSerfResponseHandler = Serf_HandleResponse; 466 *outSerfResponseHandlerBaton = this; 467 468 return APR_SUCCESS; 469 } 470 471 serf_bucket_t* SerfRequestProcessor::acceptSerfResponse( serf_request_t * inSerfRequest, 472 serf_bucket_t * inSerfStreamBucket, 473 apr_pool_t * inAprPool ) 474 { 475 mbAcceptSerfResponseCalled = true; 476 return mrSerfSession.acceptSerfResponse( inSerfRequest, 477 inSerfStreamBucket, 478 inAprPool ); 479 } 480 481 apr_status_t SerfRequestProcessor::handleSerfResponse( serf_request_t * inSerfRequest, 482 serf_bucket_t * inSerfResponseBucket, 483 apr_pool_t * inAprPool ) 484 { 485 mbHandleSerfResponseCalled = true; 486 487 // some general response handling and error handling 488 { 489 if ( !inSerfResponseBucket ) 490 { 491 /* A NULL response can come back if the request failed completely */ 492 mbProcessingDone = true; 493 return APR_EGENERAL; 494 } 495 496 serf_status_line sl; 497 apr_status_t status = serf_bucket_response_status( inSerfResponseBucket, &sl ); 498 if ( status ) 499 { 500 mbProcessingDone = false; // allow another try in order to get a response 501 return status; 502 } 503 // TODO - check, if response status code handling is correct 504 mnHTTPStatusCode = ( sl.version != 0 && sl.code >= 0 ) 505 ? static_cast< sal_uInt16 >( sl.code ) 506 : SC_NONE; 507 if ( sl.reason ) 508 { 509 mHTTPStatusCodeText = ::rtl::OUString::createFromAscii( sl.reason ); 510 } 511 if ( ( sl.version == 0 || sl.code < 0 ) || 512 mnHTTPStatusCode >= 300 ) 513 { 514 if ( mnHTTPStatusCode == 301 || 515 mnHTTPStatusCode == 302 || 516 mnHTTPStatusCode == 303 || 517 mnHTTPStatusCode == 307 ) 518 { 519 // new location for certain redirections 520 serf_bucket_t *headers = serf_bucket_response_get_headers( inSerfResponseBucket ); 521 const char* location = serf_bucket_headers_get( headers, "Location" ); 522 if ( location ) 523 { 524 mRedirectLocation = rtl::OUString::createFromAscii( location ); 525 } 526 mbProcessingDone = true; 527 return APR_EGENERAL; 528 } 529 else if ( mrSerfSession.isHeadRequestInProgress() && 530 ( mnHTTPStatusCode == 401 || mnHTTPStatusCode == 407 ) ) 531 { 532 // keep going as authentication is not required on HEAD request. 533 // the response already contains header fields. 534 } 535 else 536 { 537 mbProcessingDone = true; 538 return APR_EGENERAL; 539 } 540 } 541 } 542 543 // request specific processing of the response bucket 544 apr_status_t status = APR_SUCCESS; 545 mbProcessingDone = mpProcImpl->processSerfResponseBucket( inSerfRequest, 546 inSerfResponseBucket, 547 inAprPool, 548 status ); 549 550 return status; 551 } 552 553 } // namespace http_dav_ucp 554 555