xref: /AOO41X/main/ucb/source/ucp/webdav/SerfRequestProcessor.cxx (revision 25eaca47a72d3c102f3d70b4198d37f6e3072df4)
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     switch ( inStatus )
331     {
332     case APR_EGENERAL:
333         // general error; <mnHTTPStatusCode> provides more information
334         {
335             // TODO: reactivate special handling copied from neon!?
336             /*
337             if ( mnHTTPStatusCode == SC_LOCKED )
338             {
339                 if ( m_aSerfLockStore.findByUri(
340                          makeAbsoluteURL( inPath ) ) == 0 )
341                 {
342                     // locked by 3rd party
343                     throw DAVException( DAVException::DAV_LOCKED );
344                 }
345                 else
346                 {
347                     // locked by ourself
348                     throw DAVException( DAVException::DAV_LOCKED_SELF );
349                 }
350             }
351 
352             // Special handling for 400 and 412 status codes, which may indicate
353             // that a lock previously obtained by us has been released meanwhile
354             // by the server. Unfortunately, RFC is not clear at this point,
355             // thus server implementations behave different...
356             else if ( mnHTTPStatusCode == SC_BAD_REQUEST || mnHTTPStatusCode == SC_PRECONDITION_FAILED )
357             {
358                 if ( removeExpiredLocktoken( makeAbsoluteURL( inPath ), rEnv ) )
359                     throw DAVException( DAVException::DAV_LOCK_EXPIRED );
360             }
361             */
362             switch ( mnHTTPStatusCode )
363             {
364             case SC_NONE:
365                 if ( !mbSetupSerfRequestCalled )
366                 {
367                     mpDAVException = new DAVException( DAVException::DAV_HTTP_LOOKUP,
368                                                        SerfUri::makeConnectionEndPointString( mrSerfSession.getHostName(),
369                                                                                               mrSerfSession.getPort() ) );
370                 }
371                 else
372                 {
373                     mpDAVException = new DAVException( DAVException::DAV_HTTP_ERROR,
374                                                        mHTTPStatusCodeText,
375                                                        mnHTTPStatusCode );
376                 }
377                 break;
378             case SC_MOVED_PERMANENTLY:
379             case SC_MOVED_TEMPORARILY:
380             case SC_SEE_OTHER:
381             case SC_TEMPORARY_REDIRECT:
382                 mpDAVException = new DAVException( DAVException::DAV_HTTP_REDIRECT,
383                                                    mRedirectLocation );
384                 break;
385             default:
386                 mpDAVException = new DAVException( DAVException::DAV_HTTP_ERROR,
387                                                    mHTTPStatusCodeText,
388                                                    mnHTTPStatusCode );
389                 break;
390             }
391         }
392         break;
393 
394     default:
395         mpDAVException = new DAVException( DAVException::DAV_HTTP_ERROR );
396         break;
397     }
398 
399 }
400 
401 apr_status_t SerfRequestProcessor::provideSerfCredentials( char ** outUsername,
402                                          char ** outPassword,
403                                          serf_request_t * inRequest,
404                                          int inCode,
405                                          const char *inAuthProtocol,
406                                          const char *inRealm,
407                                          apr_pool_t *inAprPool )
408 {
409     return mrSerfSession.provideSerfCredentials( outUsername,
410                                                  outPassword,
411                                                  inRequest,
412                                                  inCode,
413                                                  inAuthProtocol,
414                                                  inRealm,
415                                                  inAprPool );
416 }
417 
418 apr_status_t SerfRequestProcessor::setupSerfRequest( serf_request_t * inSerfRequest,
419                                    serf_bucket_t ** outSerfRequestBucket,
420                                    serf_response_acceptor_t * outSerfResponseAcceptor,
421                                    void ** outSerfResponseAcceptorBaton,
422                                    serf_response_handler_t * outSerfResponseHandler,
423                                    void ** outSerfResponseHandlerBaton,
424                                    apr_pool_t * /*inAprPool*/ )
425 {
426     mbSetupSerfRequestCalled = true;
427     *outSerfRequestBucket = mpProcImpl->createSerfRequestBucket( inSerfRequest );
428 
429     // apply callbacks for accepting response and handling response
430     *outSerfResponseAcceptor = Serf_AcceptResponse;
431     *outSerfResponseAcceptorBaton = this;
432     *outSerfResponseHandler = Serf_HandleResponse;
433     *outSerfResponseHandlerBaton = this;
434 
435     return APR_SUCCESS;
436 }
437 
438 serf_bucket_t* SerfRequestProcessor::acceptSerfResponse( serf_request_t * inSerfRequest,
439                                                          serf_bucket_t * inSerfStreamBucket,
440                                                          apr_pool_t * inAprPool )
441 {
442     mbAcceptSerfResponseCalled = true;
443     return mrSerfSession.acceptSerfResponse( inSerfRequest,
444                                              inSerfStreamBucket,
445                                              inAprPool );
446 }
447 
448 apr_status_t SerfRequestProcessor::handleSerfResponse( serf_request_t * inSerfRequest,
449                                                        serf_bucket_t * inSerfResponseBucket,
450                                                        apr_pool_t * inAprPool )
451 {
452     mbHandleSerfResponseCalled = true;
453 
454     // some general response handling and error handling
455     {
456         if ( !inSerfResponseBucket )
457         {
458             /* A NULL response can come back if the request failed completely */
459             mbProcessingDone = true;
460             return APR_EGENERAL;
461         }
462 
463         serf_status_line sl;
464         apr_status_t status = serf_bucket_response_status( inSerfResponseBucket, &sl );
465         if ( status )
466         {
467             mbProcessingDone = false; // allow another try in order to get a response
468             return status;
469         }
470         // TODO - check, if response status code handling is correct
471         mnHTTPStatusCode = ( sl.version != 0 && sl.code >= 0 )
472                            ? static_cast< sal_uInt16 >( sl.code )
473                            : SC_NONE;
474         if ( sl.reason )
475         {
476             mHTTPStatusCodeText = ::rtl::OUString::createFromAscii( sl.reason );
477         }
478         if ( ( sl.version == 0 || sl.code < 0 ) ||
479              mnHTTPStatusCode >= 300 )
480         {
481             if ( mnHTTPStatusCode == 301 ||
482                  mnHTTPStatusCode == 302 ||
483                  mnHTTPStatusCode == 303 ||
484                  mnHTTPStatusCode == 307 )
485             {
486                 // new location for certain redirections
487                 serf_bucket_t *headers = serf_bucket_response_get_headers( inSerfResponseBucket );
488                 const char* location = serf_bucket_headers_get( headers, "Location" );
489                 if ( location )
490                 {
491                     mRedirectLocation = rtl::OUString::createFromAscii( location );
492                 }
493                 mbProcessingDone = true;
494                 return APR_EGENERAL;
495             }
496             else if ( mrSerfSession.isHeadRequestInProgress() &&
497                       ( mnHTTPStatusCode == 401 || mnHTTPStatusCode == 407 ) )
498             {
499                 // keep going as authentication is not required on HEAD request.
500                 // the response already contains header fields.
501             }
502             else
503             {
504                 mbProcessingDone = true;
505                 return APR_EGENERAL;
506             }
507         }
508     }
509 
510     // request specific processing of the response bucket
511     apr_status_t status = APR_SUCCESS;
512     mbProcessingDone = mpProcImpl->processSerfResponseBucket( inSerfRequest,
513                                                               inSerfResponseBucket,
514                                                               inAprPool,
515                                                               status );
516 
517     return status;
518 }
519 
520 } // namespace http_dav_ucp
521 
522