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