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