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