xref: /AOO41X/main/ucb/source/ucp/webdav/SerfRequestProcessor.cxx (revision 49989859e53c00116107466c5a504a544b25d8d6)
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