Modified: openoffice/trunk/main/ucb/source/ucp/webdav/SerfRequestProcessor.cxx URL: http://svn.apache.org/viewvc/openoffice/trunk/main/ucb/source/ucp/webdav/SerfRequestProcessor.cxx?rev=1705199&r1=1705198&r2=1705199&view=diff ============================================================================== --- openoffice/trunk/main/ucb/source/ucp/webdav/SerfRequestProcessor.cxx (original) +++ openoffice/trunk/main/ucb/source/ucp/webdav/SerfRequestProcessor.cxx Thu Sep 24 23:49:58 2015 @@ -30,6 +30,9 @@ #include <apr_strings.h> +//to examine returned http code +#include "DAVException.hxx" + namespace http_dav_ucp { @@ -111,11 +114,19 @@ bool SerfRequestProcessor::processPropFi // PROPPATCH bool SerfRequestProcessor::processPropPatch( const std::vector< ProppatchValue > & inProperties, + const com::sun::star::ucb::Lock inLock, apr_status_t& outSerfStatus ) { + char * inLockToken = static_cast<char*>(0); + if(inLock.LockTokens.getLength() > 0) + { + inLockToken = apr_psprintf( mrSerfSession.getAprPool(), "(<%s>)", + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ).getStr() ); + } mpProcImpl = createPropPatchReqProcImpl( mPathStr, mrSerfSession.getRequestEnvironment().m_aRequestHeaders, - inProperties ); + inProperties, + inLockToken ); outSerfStatus = runProcessor(); return outSerfStatus == APR_SUCCESS; @@ -194,11 +205,19 @@ bool SerfRequestProcessor::processHead( // PUT bool SerfRequestProcessor::processPut( const char* inData, apr_size_t inDataLen, + const com::sun::star::ucb::Lock inLock, apr_status_t& outSerfStatus ) { + char * inLockToken = static_cast<char*>(0); + if(inLock.LockTokens.getLength() > 0) + { + inLockToken = apr_psprintf( mrSerfSession.getAprPool(), "(<%s>)", + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ).getStr() ); + } mpProcImpl = createPutReqProcImpl( mPathStr, mrSerfSession.getRequestEnvironment().m_aRequestHeaders, inData, + inLockToken, inDataLen ); outSerfStatus = runProcessor(); @@ -210,6 +229,7 @@ bool SerfRequestProcessor::processPost( apr_size_t inDataLen, const rtl::OUString & inContentType, const rtl::OUString & inReferer, + const com::sun::star::ucb::Lock inLock, const com::sun::star::uno::Reference< SerfInputStream >& xioInStrm, apr_status_t& outSerfStatus ) { @@ -217,10 +237,17 @@ bool SerfRequestProcessor::processPost( rtl::OUStringToOString( inContentType, RTL_TEXTENCODING_UTF8 ).getStr() ); mReferer = apr_pstrdup( mrSerfSession.getAprPool(), rtl::OUStringToOString( inReferer, RTL_TEXTENCODING_UTF8 ).getStr() ); + char * inLockToken = static_cast<char*>(0); + if(inLock.LockTokens.getLength() > 0) + { + inLockToken = apr_psprintf( mrSerfSession.getAprPool(), "(<%s>)", + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ).getStr() ); + } mpProcImpl = createPostReqProcImpl( mPathStr, mrSerfSession.getRequestEnvironment().m_aRequestHeaders, inData, inDataLen, + inLockToken, mContentType, mReferer, xioInStrm ); @@ -234,6 +261,7 @@ bool SerfRequestProcessor::processPost( apr_size_t inDataLen, const rtl::OUString & inContentType, const rtl::OUString & inReferer, + const com::sun::star::ucb::Lock inLock, const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xioOutStrm, apr_status_t& outSerfStatus ) { @@ -241,10 +269,17 @@ bool SerfRequestProcessor::processPost( rtl::OUStringToOString( inContentType, RTL_TEXTENCODING_UTF8 ).getStr() ); mReferer = apr_pstrdup( mrSerfSession.getAprPool(), rtl::OUStringToOString( inReferer, RTL_TEXTENCODING_UTF8 ).getStr() ); + char * inLockToken = static_cast<char*>(0); + if(inLock.LockTokens.getLength() > 0) + { + inLockToken = apr_psprintf( mrSerfSession.getAprPool(), "(<%s>)", + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ).getStr() ); + } mpProcImpl = createPostReqProcImpl( mPathStr, mrSerfSession.getRequestEnvironment().m_aRequestHeaders, inData, inDataLen, + inLockToken, mContentType, mReferer, xioOutStrm ); @@ -254,20 +289,36 @@ bool SerfRequestProcessor::processPost( } // DELETE -bool SerfRequestProcessor::processDelete( apr_status_t& outSerfStatus ) +bool SerfRequestProcessor::processDelete( const com::sun::star::ucb::Lock inLock, + apr_status_t& outSerfStatus ) { + char * inLockToken = static_cast<char*>(0); + if(inLock.LockTokens.getLength() > 0) + { + inLockToken = apr_psprintf( mrSerfSession.getAprPool(), "(<%s>)", + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ).getStr() ); + } mpProcImpl = createDeleteReqProcImpl( mPathStr, - mrSerfSession.getRequestEnvironment().m_aRequestHeaders ); + mrSerfSession.getRequestEnvironment().m_aRequestHeaders, + inLockToken ); outSerfStatus = runProcessor(); return outSerfStatus == APR_SUCCESS; } // MKCOL -bool SerfRequestProcessor::processMkCol( apr_status_t& outSerfStatus ) +bool SerfRequestProcessor::processMkCol( const com::sun::star::ucb::Lock inLock, + apr_status_t& outSerfStatus ) { + char * inLockToken = static_cast<char*>(0); + if(inLock.LockTokens.getLength() > 0) + { + inLockToken = apr_psprintf( mrSerfSession.getAprPool(), "(<%s>)", + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ).getStr() ); + } mpProcImpl = createMkColReqProcImpl( mPathStr, - mrSerfSession.getRequestEnvironment().m_aRequestHeaders ); + mrSerfSession.getRequestEnvironment().m_aRequestHeaders, + inLockToken ); outSerfStatus = runProcessor(); return outSerfStatus == APR_SUCCESS; @@ -276,14 +327,22 @@ bool SerfRequestProcessor::processMkCol( // COPY bool SerfRequestProcessor::processCopy( const rtl::OUString & inDestinationPath, const bool inOverwrite, + const com::sun::star::ucb::Lock inLock, apr_status_t& outSerfStatus ) { mDestPathStr = apr_pstrdup( mrSerfSession.getAprPool(), rtl::OUStringToOString( inDestinationPath, RTL_TEXTENCODING_UTF8 ).getStr() ); + char * inLockToken = static_cast<char*>(0); + if(inLock.LockTokens.getLength() > 0) + { + inLockToken = apr_psprintf( mrSerfSession.getAprPool(), "(<%s>)", + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ).getStr() ); + } mpProcImpl = createCopyReqProcImpl( mPathStr, mrSerfSession.getRequestEnvironment().m_aRequestHeaders, mDestPathStr, - inOverwrite ); + inOverwrite, + inLockToken ); outSerfStatus = runProcessor(); return outSerfStatus == APR_SUCCESS; @@ -292,14 +351,95 @@ bool SerfRequestProcessor::processCopy( // MOVE bool SerfRequestProcessor::processMove( const rtl::OUString & inDestinationPath, const bool inOverwrite, + const com::sun::star::ucb::Lock inLock, apr_status_t& outSerfStatus ) { mDestPathStr = apr_pstrdup( mrSerfSession.getAprPool(), rtl::OUStringToOString( inDestinationPath, RTL_TEXTENCODING_UTF8 ).getStr() ); + char * inLockToken = static_cast<char*>(0); + if(inLock.LockTokens.getLength() > 0) + { + inLockToken = apr_psprintf( mrSerfSession.getAprPool(), "(<%s>)", + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ).getStr() ); + } mpProcImpl = createMoveReqProcImpl( mPathStr, mrSerfSession.getRequestEnvironment().m_aRequestHeaders, mDestPathStr, - inOverwrite ); + inOverwrite, + inLockToken ); + outSerfStatus = runProcessor(); + + return outSerfStatus == APR_SUCCESS; +} + +//LOCK creating a new lock +bool SerfRequestProcessor::processLock( const rtl::OUString & inDestinationPath, + const com::sun::star::ucb::Lock& inLock, + DAVPropertyValue & outLock, + apr_status_t& outSerfStatus ) +{ + mDestPathStr = apr_pstrdup( mrSerfSession.getAprPool(), + rtl::OUStringToOString( inDestinationPath, RTL_TEXTENCODING_UTF8 ).getStr() ); + char * Timeout; + if(inLock.Timeout == -1) + Timeout = apr_psprintf( mrSerfSession.getAprPool(), "Infinite" ); + else + Timeout = apr_psprintf( mrSerfSession.getAprPool(), "Second-%ld", inLock.Timeout ); + + mpProcImpl = createLockReqProcImpl( mPathStr, + mrSerfSession.getRequestEnvironment().m_aRequestHeaders, + inLock, + Timeout, + outLock); + outSerfStatus = runProcessor(); + + return outSerfStatus == APR_SUCCESS; +} + +//LOCK refresh an existing lock +bool SerfRequestProcessor::processLockRefresh( const rtl::OUString & inDestinationPath, + const com::sun::star::ucb::Lock& inLock, + DAVPropertyValue & outLock, + apr_status_t& outSerfStatus ) +{ + mDestPathStr = apr_pstrdup( mrSerfSession.getAprPool(), + rtl::OUStringToOString( inDestinationPath, RTL_TEXTENCODING_UTF8 ).getStr() ); + char * Timeout; + if(inLock.Timeout == -1) + Timeout = apr_psprintf( mrSerfSession.getAprPool(), "Infinite" ); + else + Timeout = apr_psprintf( mrSerfSession.getAprPool(), "Second-%ld", inLock.Timeout ); + + char * inLockToken = apr_psprintf( mrSerfSession.getAprPool(), "(<%s>)", + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ).getStr() ); + + mpProcImpl = createLockRefreshProcImpl( mPathStr, + mrSerfSession.getRequestEnvironment().m_aRequestHeaders, + inLock, + inLockToken, + Timeout, + outLock); + outSerfStatus = runProcessor(); + + return outSerfStatus == APR_SUCCESS; +} + +//ULOCK unlock an existing lock +bool SerfRequestProcessor::processUnlock( const rtl::OUString & inDestinationPath, + const com::sun::star::ucb::Lock& inLock, + apr_status_t& outSerfStatus ) +{ + mDestPathStr = apr_pstrdup( mrSerfSession.getAprPool(), + rtl::OUStringToOString( inDestinationPath, RTL_TEXTENCODING_UTF8 ).getStr() ); + + char * aToken = apr_psprintf( mrSerfSession.getAprPool(), "<%s>", + rtl::OUStringToOString(inLock.LockTokens[0], RTL_TEXTENCODING_UTF8 ).getStr() ); + + mpProcImpl = createUnlockProcImpl( mPathStr, + mrSerfSession.getRequestEnvironment().m_aRequestHeaders, + inLock, + aToken ); + outSerfStatus = runProcessor(); return outSerfStatus == APR_SUCCESS; @@ -316,7 +456,8 @@ apr_status_t SerfRequestProcessor::runPr } // create serf request - serf_connection_request_create( mrSerfSession.getSerfConnection(), + OSL_ASSERT(mrSerfSession.getSerfConnection() != NULL); + serf_connection_request_create( mrSerfSession.getSerfConnection(), Serf_SetupRequest, this ); @@ -327,15 +468,19 @@ apr_status_t SerfRequestProcessor::runPr apr_pool_t* pAprPool = mrSerfSession.getAprPool(); while ( true ) { - status = serf_context_run( pSerfContext, - SERF_DURATION_FOREVER, + status = serf_context_run( pSerfContext, + SERF_DURATION_FOREVER, pAprPool ); if ( APR_STATUS_IS_TIMEUP( status ) ) { continue; } - if ( status != APR_SUCCESS ) + if ( status != APR_SUCCESS ) { +#if OSL_DEBUG_LEVEL > 0 + char buff[512]; + OSL_TRACE("SerfRequestProcessor::runProcessor, status != APR_SUCCESS: %d (%s)",status, apr_strerror(status, buff, 512)); +#endif break; } if ( mbProcessingDone ) @@ -356,6 +501,7 @@ void SerfRequestProcessor::postprocessPr return; } + OSL_TRACE("SerfRequestProcessor::postprocessProcessor:%d",__LINE__); switch ( inStatus ) { case APR_EGENERAL: @@ -379,8 +525,8 @@ void SerfRequestProcessor::postprocessPr } else { - mpDAVException = new DAVException( DAVException::DAV_HTTP_ERROR, - mHTTPStatusCodeText, + mpDAVException = new DAVException( DAVException::DAV_HTTP_ERROR, + mHTTPStatusCodeText, mnHTTPStatusCode ); } break; @@ -388,12 +534,17 @@ void SerfRequestProcessor::postprocessPr case SC_MOVED_TEMPORARILY: case SC_SEE_OTHER: case SC_TEMPORARY_REDIRECT: - mpDAVException = new DAVException( DAVException::DAV_HTTP_REDIRECT, + mpDAVException = new DAVException( DAVException::DAV_HTTP_REDIRECT, mRedirectLocation ); break; + case SC_LOCKED: + mpDAVException = new DAVException( DAVException::DAV_LOCKED, + mHTTPStatusCodeText, + mnHTTPStatusCode ); + break; default: - mpDAVException = new DAVException( DAVException::DAV_HTTP_ERROR, - mHTTPStatusCodeText, + mpDAVException = new DAVException( DAVException::DAV_HTTP_ERROR, + mHTTPStatusCodeText, mnHTTPStatusCode ); break; } @@ -404,13 +555,12 @@ void SerfRequestProcessor::postprocessPr mpDAVException = new DAVException( DAVException::DAV_HTTP_ERROR ); break; } - } -apr_status_t SerfRequestProcessor::provideSerfCredentials( char ** outUsername, +apr_status_t SerfRequestProcessor::provideSerfCredentials( char ** outUsername, char ** outPassword, - serf_request_t * inRequest, - int inCode, + serf_request_t * inRequest, + int inCode, const char *inAuthProtocol, const char *inRealm, apr_pool_t *inAprPool ) @@ -486,7 +636,7 @@ apr_status_t SerfRequestProcessor::handl // some general response handling and error handling { - if ( !inSerfResponseBucket ) + if ( !inSerfResponseBucket ) { /* A NULL response can come back if the request failed completely */ mbProcessingDone = true; @@ -495,11 +645,29 @@ apr_status_t SerfRequestProcessor::handl serf_status_line sl; apr_status_t status = serf_bucket_response_status( inSerfResponseBucket, &sl ); - if ( status ) + if ( status ) { mbProcessingDone = false; // allow another try in order to get a response return status; } + serf_bucket_t *headers = serf_bucket_response_get_headers( inSerfResponseBucket ); + + // check header according: + // http://tools.ietf.org/html/rfc7231#section-7.4.2 + // need to do this so we can adjust the protocol accordingly + // serf_bucket_headers_get is case independent + const char* server = serf_bucket_headers_get( headers, "server" ); + if( server ) + { + //update the server type on session + mrSerfSession.setServerHeaderField( ::rtl::OUString::createFromAscii( server ) ); + } + //the following extension is MS IIS specific, + //see https://msdn.microsoft.com/en-us/library/cc250064.aspx + //site last checked on 2015-03-02 + //TODO i126305 need to be added when serf is updated to a version supporting Windows authentication + //const char* msDavExtErr = serf_bucket_headers_get( headers, "X-MSDAVEXT_ERROR" ); + // TODO - check, if response status code handling is correct mnHTTPStatusCode = ( sl.version != 0 && sl.code >= 0 ) ? static_cast< sal_uInt16 >( sl.code ) @@ -508,7 +676,7 @@ apr_status_t SerfRequestProcessor::handl { mHTTPStatusCodeText = ::rtl::OUString::createFromAscii( sl.reason ); } - if ( ( sl.version == 0 || sl.code < 0 ) || + if ( ( sl.version == 0 || sl.code < 0 ) || mnHTTPStatusCode >= 300 ) { if ( mnHTTPStatusCode == 301 || @@ -517,7 +685,6 @@ apr_status_t SerfRequestProcessor::handl mnHTTPStatusCode == 307 ) { // new location for certain redirections - serf_bucket_t *headers = serf_bucket_response_get_headers( inSerfResponseBucket ); const char* location = serf_bucket_headers_get( headers, "Location" ); if ( location ) {
Modified: openoffice/trunk/main/ucb/source/ucp/webdav/SerfRequestProcessor.hxx URL: http://svn.apache.org/viewvc/openoffice/trunk/main/ucb/source/ucp/webdav/SerfRequestProcessor.hxx?rev=1705199&r1=1705198&r2=1705199&view=diff ============================================================================== --- openoffice/trunk/main/ucb/source/ucp/webdav/SerfRequestProcessor.hxx (original) +++ openoffice/trunk/main/ucb/source/ucp/webdav/SerfRequestProcessor.hxx Thu Sep 24 23:49:58 2015 @@ -32,6 +32,7 @@ #include "DAVResource.hxx" #include "DAVException.hxx" +#include "SerfTypes.hxx" #include "SerfInputStream.hxx" #include <com/sun/star/io/XOutputStream.hpp> @@ -62,6 +63,7 @@ public: // PROPPATCH bool processPropPatch( const std::vector< ProppatchValue > & inProperties, + const com::sun::star::ucb::Lock inLock, apr_status_t& outSerfStatus ); // GET @@ -92,6 +94,7 @@ public: // PUT bool processPut( const char* inData, apr_size_t inDataLen, + const com::sun::star::ucb::Lock inLock, apr_status_t& outSerfStatus ); // POST @@ -99,6 +102,7 @@ public: apr_size_t inDataLen, const rtl::OUString & inContentType, const rtl::OUString & inReferer, + const com::sun::star::ucb::Lock inLock, const com::sun::star::uno::Reference< SerfInputStream >& xioInStrm, apr_status_t& outSerfStatus ); @@ -107,25 +111,47 @@ public: apr_size_t inDataLen, const rtl::OUString & inContentType, const rtl::OUString & inReferer, + const com::sun::star::ucb::Lock inLock, const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xioOutStrm, apr_status_t& outSerfStatus ); // DELETE - bool processDelete( apr_status_t& outSerfStatus ); + bool processDelete( const com::sun::star::ucb::Lock inLock, + apr_status_t& outSerfStatus ); // MKCOL - bool processMkCol( apr_status_t& outSerfStatus ); + bool processMkCol( const com::sun::star::ucb::Lock inLock, + apr_status_t& outSerfStatus ); // COPY bool processCopy( const rtl::OUString & inDestinationPath, const bool inOverwrite, + const com::sun::star::ucb::Lock inLock, apr_status_t& outSerfStatus ); // MOVE bool processMove( const rtl::OUString & inDestinationPath, const bool inOverwrite, + const com::sun::star::ucb::Lock inLock, apr_status_t& outSerfStatus ); + // LOCK + bool processLock( const rtl::OUString & inDestinationPath, + const com::sun::star::ucb::Lock& inLock, + DAVPropertyValue & outLock, + apr_status_t& outSerfStatus ); + + // LOCK refresh + bool processLockRefresh( const rtl::OUString & inDestinationPath, + const com::sun::star::ucb::Lock& inLock, + DAVPropertyValue & outLock, + apr_status_t& outSerfStatus ); + + //UNLOCK + bool processUnlock( const rtl::OUString & inDestinationPath, + const com::sun::star::ucb::Lock& inLock, + apr_status_t& outSerfStatus ); + apr_status_t provideSerfCredentials( char ** outUsername, char ** outPassword, serf_request_t * inRequest, Modified: openoffice/trunk/main/ucb/source/ucp/webdav/SerfRequestProcessorImplFac.cxx URL: http://svn.apache.org/viewvc/openoffice/trunk/main/ucb/source/ucp/webdav/SerfRequestProcessorImplFac.cxx?rev=1705199&r1=1705198&r2=1705199&view=diff ============================================================================== --- openoffice/trunk/main/ucb/source/ucp/webdav/SerfRequestProcessorImplFac.cxx (original) +++ openoffice/trunk/main/ucb/source/ucp/webdav/SerfRequestProcessorImplFac.cxx Thu Sep 24 23:49:58 2015 @@ -22,6 +22,7 @@ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_ucb.hxx" +#include "SerfTypes.hxx" #include "SerfRequestProcessorImplFac.hxx" #include "SerfPropFindReqProcImpl.hxx" #include "SerfPropPatchReqProcImpl.hxx" @@ -33,6 +34,9 @@ #include "SerfMkColReqProcImpl.hxx" #include "SerfCopyReqProcImpl.hxx" #include "SerfMoveReqProcImpl.hxx" +#include "SerfLockReqProcImpl.hxx" +#include "SerfLockRefreshProcImpl.hxx" +#include "SerfUnlockProcImpl.hxx" namespace http_dav_ucp { @@ -64,11 +68,13 @@ namespace http_dav_ucp SerfRequestProcessorImpl* createPropPatchReqProcImpl( const char* inPath, const DAVRequestHeaders& inRequestHeaders, - const std::vector< ProppatchValue > & inProperties ) + const std::vector< ProppatchValue > & inProperties, + const char* inLockToken ) { SerfRequestProcessorImpl* pReqProcImpl = new SerfPropPatchReqProcImpl( inPath, inRequestHeaders, - inProperties ); + inProperties, + inLockToken ); return pReqProcImpl; } @@ -136,11 +142,13 @@ namespace http_dav_ucp SerfRequestProcessorImpl* createPutReqProcImpl( const char* inPath, const DAVRequestHeaders& inRequestHeaders, const char* inData, + const char* inLockToken, apr_size_t inDataLen ) { SerfRequestProcessorImpl* pReqProcImpl = new SerfPutReqProcImpl( inPath, inRequestHeaders, inData, + inLockToken, inDataLen ); return pReqProcImpl; } @@ -149,6 +157,7 @@ namespace http_dav_ucp const DAVRequestHeaders& inRequestHeaders, const char* inData, apr_size_t inDataLen, + const char* inLockToken, const char* inContentType, const char* inReferer, const com::sun::star::uno::Reference< SerfInputStream >& xioInStrm ) @@ -157,6 +166,7 @@ namespace http_dav_ucp inRequestHeaders, inData, inDataLen, + inLockToken, inContentType, inReferer, xioInStrm ); @@ -167,6 +177,7 @@ namespace http_dav_ucp const DAVRequestHeaders& inRequestHeaders, const char* inData, apr_size_t inDataLen, + const char* inLockToken, const char* inContentType, const char* inReferer, const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xioOutStrm ) @@ -175,6 +186,7 @@ namespace http_dav_ucp inRequestHeaders, inData, inDataLen, + inLockToken, inContentType, inReferer, xioOutStrm ); @@ -182,42 +194,92 @@ namespace http_dav_ucp } SerfRequestProcessorImpl* createDeleteReqProcImpl( const char* inPath, - const DAVRequestHeaders& inRequestHeaders ) + const DAVRequestHeaders& inRequestHeaders, + const char * inLockToken ) { SerfRequestProcessorImpl* pReqProcImpl = new SerfDeleteReqProcImpl( inPath, - inRequestHeaders ); + inRequestHeaders, + inLockToken ); return pReqProcImpl; } SerfRequestProcessorImpl* createMkColReqProcImpl( const char* inPath, - const DAVRequestHeaders& inRequestHeaders ) + const DAVRequestHeaders& inRequestHeaders, + const char * inLockToken ) { SerfRequestProcessorImpl* pReqProcImpl = new SerfMkColReqProcImpl( inPath, - inRequestHeaders ); + inRequestHeaders, + inLockToken ); return pReqProcImpl; } SerfRequestProcessorImpl* createCopyReqProcImpl( const char* inSourcePath, const DAVRequestHeaders& inRequestHeaders, const char* inDestinationPath, - const bool inOverwrite ) + const bool inOverwrite, + const char* inLockToken ) { SerfRequestProcessorImpl* pReqProcImpl = new SerfCopyReqProcImpl( inSourcePath, inRequestHeaders, inDestinationPath, - inOverwrite ); + inOverwrite, + inLockToken ); return pReqProcImpl; } SerfRequestProcessorImpl* createMoveReqProcImpl( const char* inSourcePath, const DAVRequestHeaders& inRequestHeaders, const char* inDestinationPath, - const bool inOverwrite ) + const bool inOverwrite, + const char* inLockToken ) { SerfRequestProcessorImpl* pReqProcImpl = new SerfMoveReqProcImpl( inSourcePath, inRequestHeaders, inDestinationPath, - inOverwrite ); + inOverwrite, + inLockToken ); + return pReqProcImpl; + } + + SerfRequestProcessorImpl* createLockReqProcImpl( const char* inSourcePath, + const DAVRequestHeaders& inRequestHeaders, + const ucb::Lock& inLock, + const char* inTimeout, + DAVPropertyValue & outLock) + { + SerfRequestProcessorImpl* pReqProcImpl = new SerfLockReqProcImpl( inSourcePath, + inRequestHeaders, + inLock, + inTimeout, + outLock); + return pReqProcImpl; + } + + SerfRequestProcessorImpl* createLockRefreshProcImpl( const char* inSourcePath, + const DAVRequestHeaders& inRequestHeaders, + const ucb::Lock& inLock, + const char* inLockToken, + const char* inTimeout, + DAVPropertyValue & outLock) + { + SerfRequestProcessorImpl* pReqProcImpl = new SerfLockRefreshProcImpl( inSourcePath, + inRequestHeaders, + inLock, + inLockToken, + inTimeout, + outLock); + return pReqProcImpl; + } + + SerfRequestProcessorImpl* createUnlockProcImpl( const char* inSourcePath, + const DAVRequestHeaders& inRequestHeaders, + const ucb::Lock& inLock, + const char* inToken ) + { + SerfRequestProcessorImpl* pReqProcImpl = new SerfUnlockProcImpl( inSourcePath, + inRequestHeaders, + inLock, + inToken ); return pReqProcImpl; } Modified: openoffice/trunk/main/ucb/source/ucp/webdav/SerfRequestProcessorImplFac.hxx URL: http://svn.apache.org/viewvc/openoffice/trunk/main/ucb/source/ucp/webdav/SerfRequestProcessorImplFac.hxx?rev=1705199&r1=1705198&r2=1705199&view=diff ============================================================================== --- openoffice/trunk/main/ucb/source/ucp/webdav/SerfRequestProcessorImplFac.hxx (original) +++ openoffice/trunk/main/ucb/source/ucp/webdav/SerfRequestProcessorImplFac.hxx Thu Sep 24 23:49:58 2015 @@ -27,6 +27,7 @@ #include "DAVTypes.hxx" #include "DAVResource.hxx" +#include "SerfTypes.hxx" #include "SerfRequestProcessorImpl.hxx" #include "SerfInputStream.hxx" #include <com/sun/star/io/XOutputStream.hpp> @@ -46,7 +47,8 @@ namespace http_dav_ucp SerfRequestProcessorImpl* createPropPatchReqProcImpl( const char* inPath, const DAVRequestHeaders& inRequestHeaders, - const std::vector< ProppatchValue > & inProperties ); + const std::vector< ProppatchValue > & inProperties, + const char* inLockToken ); SerfRequestProcessorImpl* createGetReqProcImpl( const char* inPath, const DAVRequestHeaders& inRequestHeaders, @@ -76,12 +78,14 @@ namespace http_dav_ucp SerfRequestProcessorImpl* createPutReqProcImpl( const char* inPath, const DAVRequestHeaders& inRequestHeaders, const char* inData, + const char* inLockToken, apr_size_t inDataLen ); SerfRequestProcessorImpl* createPostReqProcImpl( const char* inPath, const DAVRequestHeaders& inRequestHeaders, const char* inData, apr_size_t inDataLen, + const char* inLockToken, const char* inContentType, const char* inReferer, const com::sun::star::uno::Reference< SerfInputStream >& xioInStrm ); @@ -90,25 +94,48 @@ namespace http_dav_ucp const DAVRequestHeaders& inRequestHeaders, const char* inData, apr_size_t inDataLen, + const char* inLockToken, const char* inContentType, const char* inReferer, const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xioOutStrm ); SerfRequestProcessorImpl* createDeleteReqProcImpl( const char* inPath, - const DAVRequestHeaders& inRequestHeaders ); + const DAVRequestHeaders& inRequestHeaders, + const char * inLockToken ); SerfRequestProcessorImpl* createMkColReqProcImpl( const char* inPath, - const DAVRequestHeaders& inRequestHeaders ); + const DAVRequestHeaders& inRequestHeaders, + const char * inLockToken ); SerfRequestProcessorImpl* createCopyReqProcImpl( const char* inSourcePath, const DAVRequestHeaders& inRequestHeaders, const char* inDestinationPath, - const bool inOverwrite ); + const bool inOverwrite, + const char* inLockToken ); SerfRequestProcessorImpl* createMoveReqProcImpl( const char* inSourcePath, const DAVRequestHeaders& inRequestHeaders, const char* inDestinationPath, - const bool inOverwrite ); + const bool inOverwrite, + const char* inLockToken ); + + SerfRequestProcessorImpl* createLockReqProcImpl( const char* inSourcePath, + const DAVRequestHeaders& inRequestHeaders, + const ucb::Lock& inLock, + const char* inTimeout, + DAVPropertyValue & outLock ); + + SerfRequestProcessorImpl* createLockRefreshProcImpl( const char* inSourcePath, + const DAVRequestHeaders& inRequestHeaders, + const ucb::Lock& inLock, + const char* inToken, + const char* inTimeout, + DAVPropertyValue & outLock ); + + SerfRequestProcessorImpl* createUnlockProcImpl( const char* inSourcePath, + const DAVRequestHeaders& inRequestHeaders, + const ucb::Lock& inLock, + const char* inToken ); } // namespace http_dav_ucp Modified: openoffice/trunk/main/ucb/source/ucp/webdav/SerfSession.cxx URL: http://svn.apache.org/viewvc/openoffice/trunk/main/ucb/source/ucp/webdav/SerfSession.cxx?rev=1705199&r1=1705198&r2=1705199&view=diff ============================================================================== --- openoffice/trunk/main/ucb/source/ucp/webdav/SerfSession.cxx (original) +++ openoffice/trunk/main/ucb/source/ucp/webdav/SerfSession.cxx Thu Sep 24 23:49:58 2015 @@ -26,6 +26,8 @@ #include <vector> #include <string.h> #include <rtl/string.h> +#include <rtl/ustrbuf.hxx> +#include <osl/time.h> #include "comphelper/sequence.hxx" #include "ucbhelper/simplecertificatevalidationrequest.hxx" @@ -57,10 +59,9 @@ using namespace com::sun::star; using namespace http_dav_ucp; - // ------------------------------------------------------------------- // static members! -//SerfLockStore SerfSession::m_aSerfLockStore; +SerfLockStore SerfSession::m_aSerfLockStore; // ------------------------------------------------------------------- // Constructor @@ -75,6 +76,7 @@ SerfSession::SerfSession( , m_aUri( inUri ) , m_aProxyName() , m_nProxyPort( 0 ) + , m_aServerHeaderField() , m_pSerfConnection( 0 ) , m_pSerfContext( 0 ) , m_bIsHeadRequestInProgress( false ) @@ -97,6 +99,7 @@ SerfSession::~SerfSession( ) { serf_connection_close( m_pSerfConnection ); m_pSerfConnection = 0; + OSL_TRACE("SerfSession::~SerfSession: closed serf connection"); } } @@ -126,6 +129,7 @@ void SerfSession::Init() // Not yet initialized. Create new session. bCreateNewSession = true; + OSL_TRACE("SerfSession::Init: serf connection created"); } else { @@ -166,7 +170,7 @@ void SerfSession::Init() if ( m_aProxyName.getLength() ) { apr_sockaddr_t *proxy_address = NULL; - status = apr_sockaddr_info_get( &proxy_address, + status = apr_sockaddr_info_get( &proxy_address, rtl::OUStringToOString( m_aProxyName, RTL_TEXTENCODING_UTF8 ).getStr(), APR_UNSPEC, static_cast<apr_port_t>(m_nProxyPort), @@ -223,6 +227,55 @@ char* SerfSession::getHostinfo() return m_aUri.getAprUri()->hostinfo; } +// ------------------------------------------------------------------- +// helper function +// it composes the uri for lockstore registration +rtl::OUString SerfSession::composeCurrentUri(const rtl::OUString & inPath) +{ + rtl::OUString aScheme( m_aUri.GetScheme() ); + rtl::OUStringBuffer aBuf( aScheme ); + aBuf.appendAscii( "://" ); + if ( m_aUri.GetUserInfo().getLength() > 0 ) + { + aBuf.append( m_aUri.GetUserInfo() ); + aBuf.appendAscii( "@" ); + } + // Is host a numeric IPv6 address? + if ( ( m_aUri.GetHost().indexOf( ':' ) != -1 ) && + ( m_aUri.GetHost()[ 0 ] != sal_Unicode( '[' ) ) ) + { + aBuf.appendAscii( "[" ); + aBuf.append( m_aUri.GetHost() ); + aBuf.appendAscii( "]" ); + } + else + { + aBuf.append( m_aUri.GetHost() ); + } + + // append port, but only, if not default port. + bool bAppendPort = true; + sal_Int32 aPort = m_aUri.GetPort(); + switch ( aPort ) + { + case DEFAULT_HTTP_PORT: + bAppendPort = aScheme.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "http" ) ); + break; + + case DEFAULT_HTTPS_PORT: + bAppendPort = !aScheme.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "https" ) ); + break; + } + if ( bAppendPort ) + { + aBuf.appendAscii( ":" ); + aBuf.append( rtl::OUString::valueOf( aPort ) ); + } + aBuf.append( inPath ); + + rtl::OUString aUri(aBuf.makeStringAndClear() ); + return aUri; +} // ------------------------------------------------------------------- // virtual @@ -259,11 +312,11 @@ apr_status_t SerfSession::setupSerfConne apr_pool_t* /*inAprPool*/ ) { serf_bucket_t *tmpInputBkt; - tmpInputBkt = serf_context_bucket_socket_create( getSerfContext(), - inAprSocket, + tmpInputBkt = serf_context_bucket_socket_create( getSerfContext(), + inAprSocket, getSerfBktAlloc() ); - - if ( isSSLNeeded() ) + + if ( isSSLNeeded() ) { tmpInputBkt = serf_bucket_ssl_decrypt_create( tmpInputBkt, 0, @@ -276,7 +329,7 @@ apr_status_t SerfSession::setupSerfConne NULL, Serf_CertificateChainValidation, this); - serf_ssl_set_hostname( serf_bucket_ssl_decrypt_context_get( tmpInputBkt ), + serf_ssl_set_hostname( serf_bucket_ssl_decrypt_context_get( tmpInputBkt ), getHostinfo() ); *outSerfOutputBucket = serf_bucket_ssl_encrypt_create( *outSerfOutputBucket, @@ -290,10 +343,10 @@ apr_status_t SerfSession::setupSerfConne } apr_status_t SerfSession::provideSerfCredentials( bool bGiveProvidedCredentialsASecondTry, - char ** outUsername, + char ** outUsername, char ** outPassword, - serf_request_t * /*inRequest*/, - int /*inCode*/, + serf_request_t * /*inRequest*/, + int /*inCode*/, const char *inAuthProtocol, const char *inRealm, apr_pool_t *inAprPool ) @@ -600,7 +653,7 @@ serf_bucket_t* SerfSession::acceptSerfRe SerfBktAlloc ); // create response bucket - responseBkt = serf_bucket_response_create( responseBkt, + responseBkt = serf_bucket_response_create( responseBkt, SerfBktAlloc ); if ( isHeadRequestInProgress() ) @@ -693,7 +746,16 @@ void SerfSession::PROPPATCH( const rtl:: apr_status_t status = APR_SUCCESS; boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) ); + //check whether a lock on this resource is already owned + rtl::OUString aUri( composeCurrentUri( inPath ) ); + ucb::Lock inLock; + SerfLock * pLock = m_aSerfLockStore.findByUri( aUri ); + if ( pLock ) + { + inLock = pLock->getLock(); + } aReqProc->processPropPatch( inValues, + inLock, status ); HandleError( aReqProc ); @@ -843,8 +905,18 @@ void SerfSession::PUT( const rtl::OUStri if ( !getDataFromInputStream( inInputStream, aDataToSend, false ) ) throw DAVException( DAVException::DAV_INVALID_ARG ); apr_status_t status = APR_SUCCESS; + + //check whether a lock on this resource is already owned + rtl::OUString aUri( composeCurrentUri( inPath ) ); + ucb::Lock inLock; + SerfLock * pLock = m_aSerfLockStore.findByUri( aUri ); + if ( pLock ) + { + inLock = pLock->getLock(); + } aReqProc->processPut( reinterpret_cast< const char * >( aDataToSend.getConstArray() ), aDataToSend.getLength(), + inLock, status ); HandleError( aReqProc ); @@ -874,10 +946,19 @@ SerfSession::POST( const rtl::OUString & boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) ); uno::Reference< SerfInputStream > xInputStream( new SerfInputStream ); apr_status_t status = APR_SUCCESS; + //check whether a lock on this resource is already owned + rtl::OUString aUri( composeCurrentUri( inPath ) ); + ucb::Lock inLock; + SerfLock * pLock = m_aSerfLockStore.findByUri( aUri ); + if ( pLock ) + { + inLock = pLock->getLock(); + } aReqProc->processPost( reinterpret_cast< const char * >( aDataToSend.getConstArray() ), aDataToSend.getLength(), rContentType, rReferer, + inLock, xInputStream, status ); @@ -908,10 +989,19 @@ void SerfSession::POST( const rtl::OUStr boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) ); apr_status_t status = APR_SUCCESS; + //check whether a lock on this resource is already owned + rtl::OUString aUri( composeCurrentUri( inPath ) ); + ucb::Lock inLock; + SerfLock * pLock = m_aSerfLockStore.findByUri( aUri ); + if ( pLock ) + { + inLock = pLock->getLock(); + } aReqProc->processPost( reinterpret_cast< const char * >( aDataToSend.getConstArray() ), aDataToSend.getLength(), rContentType, rReferer, + inLock, oOutputStream, status ); @@ -931,7 +1021,15 @@ void SerfSession::MKCOL( const rtl::OUSt boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) ); apr_status_t status = APR_SUCCESS; - aReqProc->processMkCol( status ); + //check whether a lock on the destination resource is already owned + rtl::OUString aUri( composeCurrentUri( inPath ) ); + ucb::Lock inLock; + SerfLock * pLock = m_aSerfLockStore.findByUri( aUri ); + if ( pLock ) + { + inLock = pLock->getLock(); + } + aReqProc->processMkCol( inLock, status ); HandleError( aReqProc ); } @@ -952,8 +1050,17 @@ void SerfSession::COPY( const rtl::OUStr SerfUri theSourceUri( inSourceURL ); boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( theSourceUri.GetPath() ) ); apr_status_t status = APR_SUCCESS; + //check whether a lock on the destination resource is already owned + rtl::OUString aUri( composeCurrentUri( inDestinationURL ) ); + ucb::Lock inLock; + SerfLock * pLock = m_aSerfLockStore.findByUri( aUri ); + if ( pLock ) + { + inLock = pLock->getLock(); + } aReqProc->processCopy( inDestinationURL, (inOverWrite ? true : false), + inLock, status ); HandleError( aReqProc ); @@ -975,8 +1082,17 @@ void SerfSession::MOVE( const rtl::OUStr SerfUri theSourceUri( inSourceURL ); boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( theSourceUri.GetPath() ) ); apr_status_t status = APR_SUCCESS; + //check whether a lock on the destination resource is already owned + rtl::OUString aUri( composeCurrentUri( inDestinationURL ) ); + ucb::Lock inLock; + SerfLock * pLock = m_aSerfLockStore.findByUri( aUri ); + if ( pLock ) + { + inLock = pLock->getLock(); + } aReqProc->processMove( inDestinationURL, (inOverWrite ? true : false), + inLock, status ); HandleError( aReqProc ); @@ -995,25 +1111,33 @@ void SerfSession::DESTROY( const rtl::OU boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) ); apr_status_t status = APR_SUCCESS; - aReqProc->processDelete( status ); + //check whether a lock on this resource is already owned + rtl::OUString aUri( composeCurrentUri( inPath ) ); + ucb::Lock inLock; + SerfLock * pLock = m_aSerfLockStore.findByUri( aUri ); + if ( pLock ) + { + inLock = pLock->getLock(); + } + aReqProc->processDelete( inLock, status ); HandleError( aReqProc ); } // ------------------------------------------------------------------- -/* + namespace { sal_Int32 lastChanceToSendRefreshRequest( TimeValue const & rStart, - int timeout ) + sal_Int32 timeout ) { TimeValue aEnd; osl_getSystemTime( &aEnd ); // Try to estimate a safe absolute time for sending the // lock refresh request. - sal_Int32 lastChanceToSendRefreshRequest = -1; - if ( timeout != NE_TIMEOUT_INFINITE ) + sal_Int32 lastChanceToSendRefreshRequest = DAVINFINITY; + if ( timeout != DAVINFINITY ) { sal_Int32 calltime = aEnd.Seconds - rStart.Seconds; if ( calltime <= timeout ) @@ -1030,108 +1154,62 @@ namespace } } // namespace -*/ + // ------------------------------------------------------------------- // LOCK (set new lock) // ------------------------------------------------------------------- void SerfSession::LOCK( const ::rtl::OUString & inPath, - ucb::Lock & /*rLock*/, + ucb::Lock & rLock, const DAVRequestEnvironment & rEnv ) throw ( DAVException ) { osl::Guard< osl::Mutex > theGuard( m_aMutex ); + //before locking, search in the lock store if we already own a lock for this resource + //if present, return with exception DAV_LOCKED_SELF + rtl::OUString aUri( composeCurrentUri( inPath ) ); + SerfLock * pLock = m_aSerfLockStore.findByUri( aUri ); + if ( pLock ) + { +//already present, meaning already locked by the same AOO session and already in the lockstore +//just return, nothing to do + return; + } + Init( rEnv ); boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) ); - HandleError( aReqProc ); - /* Create a depth zero, exclusive write lock, with default timeout - * (allowing a server to pick a default). token, owner and uri are - * unset. */ - /* - SerfLock * theLock = ne_lock_create(); - - // Set the lock uri - ne_uri aUri; - ne_uri_parse( rtl::OUStringToOString( makeAbsoluteURL( inPath ), - RTL_TEXTENCODING_UTF8 ).getStr(), - &aUri ); - theLock->uri = aUri; - - // Set the lock depth - switch( rLock.Depth ) - { - case ucb::LockDepth_ZERO: - theLock->depth = NE_DEPTH_ZERO; - break; - case ucb::LockDepth_ONE: - theLock->depth = NE_DEPTH_ONE; - break; - case ucb::LockDepth_INFINITY: - theLock->depth = NE_DEPTH_INFINITE; - break; - default: - throw DAVException( DAVException::DAV_INVALID_ARG ); - } - - // Set the lock scope - switch ( rLock.Scope ) - { - case ucb::LockScope_EXCLUSIVE: - theLock->scope = ne_lockscope_exclusive; - break; - case ucb::LockScope_SHARED: - theLock->scope = ne_lockscope_shared; - break; - default: - throw DAVException( DAVException::DAV_INVALID_ARG ); - } + apr_status_t status = APR_SUCCESS; - // Set the lock timeout - theLock->timeout = (long)rLock.Timeout; + //the returned property, a sequence of locks + //only the first is used + DAVPropertyValue outLock; - // Set the lock owner - rtl::OUString aValue; - rLock.Owner >>= aValue; - theLock->owner = - ne_strdup( rtl::OUStringToOString( aValue, - RTL_TEXTENCODING_UTF8 ).getStr() ); TimeValue startCall; osl_getSystemTime( &startCall ); + aReqProc->processLock(inPath, rLock, outLock, status); - int theRetVal = ne_lock( m_pHttpSession, theLock ); + //HandleError will handle the error and throw an exception, if needed + HandleError( aReqProc ); - if ( theRetVal == NE_OK ) + if(outLock.Name.compareToAscii(RTL_CONSTASCII_STRINGPARAM( "DAV:lockdiscovery" )) == 0 ) { - m_aSerfLockStore.addLock( theLock, - this, - lastChanceToSendRefreshRequest( - startCall, theLock->timeout ) ); - - uno::Sequence< rtl::OUString > aTokens( 1 ); - aTokens[ 0 ] = rtl::OUString::createFromAscii( theLock->token ); - rLock.LockTokens = aTokens; + //got a lock, use only the first returned + uno::Sequence< ucb::Lock > aLocks; + outLock.Value >>= aLocks; + ucb::Lock aLock = aLocks[0]; - OSL_TRACE( "SerfSession::LOCK: created lock for %s. token: %s", - rtl::OUStringToOString( makeAbsoluteURL( inPath ), - RTL_TEXTENCODING_UTF8 ).getStr(), - theLock->token ); - } - else - { - ne_lock_destroy( theLock ); - - OSL_TRACE( "SerfSession::LOCK: obtaining lock for %s failed!", - rtl::OUStringToOString( makeAbsoluteURL( inPath ), - RTL_TEXTENCODING_UTF8 ).getStr() ); + SerfLock* aNewLock = new SerfLock( aLock, aUri, inPath ); + // add the store the new lock + m_aSerfLockStore.addLock(aNewLock,this, + lastChanceToSendRefreshRequest( + startCall, static_cast< sal_Int32 >(aLock.Timeout) ) ); } - HandleError( theRetVal, inPath, rEnv ); - */ } // ------------------------------------------------------------------- -// LOCK (refresh existing lock) +// LOCK (refresh existing lock from DAVResourceAccess) // ------------------------------------------------------------------- sal_Int64 SerfSession::LOCK( const ::rtl::OUString & /*inPath*/, sal_Int64 nTimeout, @@ -1172,92 +1250,102 @@ sal_Int64 SerfSession::LOCK( const ::rtl } // ------------------------------------------------------------------- -// LOCK (refresh existing lock) +// LOCK (refresh existing lock from SerfLockStore) // ------------------------------------------------------------------- -bool SerfSession::LOCK( SerfLock * /*pLock*/, - sal_Int32 & /*rlastChanceToSendRefreshRequest*/ ) +bool SerfSession::LOCK( SerfLock * pLock, + sal_Int32 & rlastChanceToSendRefreshRequest ) { osl::Guard< osl::Mutex > theGuard( m_aMutex ); + rtl::OUString inPath = pLock->getResourcePath(); - return true; - /* - // refresh existing lock. + boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) ); + apr_status_t status = APR_SUCCESS; + + //the returned property, a sequence of locks + //only the first is used + DAVPropertyValue outLock; TimeValue startCall; osl_getSystemTime( &startCall ); - if ( ne_lock_refresh( m_pHttpSession, pLock ) == NE_OK ) - { - rlastChanceToSendRefreshRequest - = lastChanceToSendRefreshRequest( startCall, pLock->timeout ); + // refresh existing lock. + aReqProc->processLockRefresh( inPath, pLock->getLock(), outLock, status); - OSL_TRACE( "Lock successfully refreshed." ); - return true; - } - else - { - OSL_TRACE( "Lock not refreshed!" ); - return false; - } - */ + // TODO: possible enhancement as the following: + // - use an interaction handler to alert the user if the lock was not refreshed, + // offering to try again with a new session, asking the user for credential, if necessary. + // This may happen if the WebDAV server goes off-line for whatever reason, or the connection is dropped for time-out + // To implement this behavior, some redesigning of the current session implementation may be needed. + // + + //HandleError will handle the error and throw an exception, if needed + HandleError( aReqProc ); + + uno::Sequence< ucb::Lock > aLocks; + outLock.Value >>= aLocks; + ucb::Lock aLock = aLocks[0]; + + //if ok, udate the lastchance refresh time in lock + rlastChanceToSendRefreshRequest + = lastChanceToSendRefreshRequest( startCall, static_cast< sal_Int32 >(aLock.Timeout) ); + + return true; } // ------------------------------------------------------------------- -// UNLOCK +// UNLOCK called from external (DAVResourceAccess) // ------------------------------------------------------------------- -void SerfSession::UNLOCK( const ::rtl::OUString & /*inPath*/, - const DAVRequestEnvironment & /*rEnv*/ ) +void SerfSession::UNLOCK( const ::rtl::OUString & inPath, + const DAVRequestEnvironment & rEnv ) throw ( DAVException ) { osl::Guard< osl::Mutex > theGuard( m_aMutex ); - /* - // get the neon lock from lock store - SerfLock * theLock - = m_aSerfLockStore.findByUri( makeAbsoluteURL( inPath ) ); - if ( !theLock ) + rtl::OUString aUri( composeCurrentUri( inPath ) ); + SerfLock * pLock = m_aSerfLockStore.findByUri( aUri ); + if ( !pLock ) + { throw DAVException( DAVException::DAV_NOT_LOCKED ); + } Init( rEnv ); - int theRetVal = ne_unlock( m_pHttpSession, theLock ); + boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) ); + apr_status_t status = APR_SUCCESS; - if ( theRetVal == NE_OK ) - { - m_aSerfLockStore.removeLock( theLock ); - ne_lock_destroy( theLock ); - } - else - { - OSL_TRACE( "SerfSession::UNLOCK: unlocking of %s failed.", - rtl::OUStringToOString( makeAbsoluteURL( inPath ), - RTL_TEXTENCODING_UTF8 ).getStr() ); - } + ucb::Lock inLock = pLock->getLock(); + //remove lock from lockstore + // so, if something goes wrong, we don't refresh it anymore + m_aSerfLockStore.removeLock(pLock); + delete pLock; - HandleError( theRetVal, inPath, rEnv ); - */ + // remove existing lock + aReqProc->processUnlock( inPath, inLock, status); + + //HandleError will handle the error and throw an exception, if needed + HandleError( aReqProc ); } // ------------------------------------------------------------------- -// UNLOCK +// UNLOCK (called from SerfLockStore) // ------------------------------------------------------------------- -bool SerfSession::UNLOCK( SerfLock * /*pLock*/ ) +bool SerfSession::UNLOCK( SerfLock * pLock ) { osl::Guard< osl::Mutex > theGuard( m_aMutex ); + rtl::OUString inPath = pLock->getResourcePath(); + + boost::shared_ptr<SerfRequestProcessor> aReqProc( createReqProc( inPath ) ); + apr_status_t status = APR_SUCCESS; + + rtl::OUString aToken; + aToken = pLock->getLock().LockTokens[0]; + + aReqProc->processUnlock( inPath, pLock->getLock(), status); + + //HandleError will handle the error and throw an exception, if needed + HandleError( aReqProc ); return true; - /* - if ( ne_unlock( m_pHttpSession, pLock ) == NE_OK ) - { - OSL_TRACE( "UNLOCK succeeded." ); - return true; - } - else - { - OSL_TRACE( "UNLOCK failed!" ); - return false; - } - */ } // ------------------------------------------------------------------- @@ -1315,6 +1403,10 @@ bool containsLocktoken( const uno::Seque */ // ------------------------------------------------------------------- +// This method doesn't seem to be used. +// In any case the default behavior is to ask a lock whith a life of 3 minutes +// it will then be refreshed automatically (see SerfLockStore class) +// In case of AOO crash the lock will expire by itself bool SerfSession::removeExpiredLocktoken( const rtl::OUString & /*inURL*/, const DAVRequestEnvironment & /*rEnv*/ ) { @@ -1612,37 +1704,3 @@ SerfSession::isDomainMatch( rtl::OUStrin } return sal_False; } - -/* -// --------------------------------------------------------------------- -rtl::OUString SerfSession::makeAbsoluteURL( rtl::OUString const & rURL ) const -{ - try - { - // Is URL relative or already absolute? - if ( rURL[ 0 ] != sal_Unicode( '/' ) ) - { - // absolute. - return rtl::OUString( rURL ); - } - else - { - ne_uri aUri; - memset( &aUri, 0, sizeof( aUri ) ); - - ne_fill_server_uri( m_pHttpSession, &aUri ); - aUri.path - = ne_strdup( rtl::OUStringToOString( - rURL, RTL_TEXTENCODING_UTF8 ).getStr() ); - SerfUri aSerfUri( &aUri ); - ne_uri_free( &aUri ); - return aSerfUri.GetURI(); - } - } - catch ( DAVException const & ) - { - } - // error. - return rtl::OUString(); -} -*/ Modified: openoffice/trunk/main/ucb/source/ucp/webdav/SerfSession.hxx URL: http://svn.apache.org/viewvc/openoffice/trunk/main/ucb/source/ucp/webdav/SerfSession.hxx?rev=1705199&r1=1705198&r2=1705199&view=diff ============================================================================== --- openoffice/trunk/main/ucb/source/ucp/webdav/SerfSession.hxx (original) +++ openoffice/trunk/main/ucb/source/ucp/webdav/SerfSession.hxx Thu Sep 24 23:49:58 2015 @@ -27,9 +27,10 @@ #include <vector> #include <boost/shared_ptr.hpp> #include <osl/mutex.hxx> +#include "DAVResource.hxx" #include "DAVSession.hxx" #include "SerfTypes.hxx" -//#include "SerfLockStore.hxx" +#include "SerfLockStore.hxx" #include "SerfUri.hxx" #include <com/sun/star/lang/XMultiServiceFactory.hpp> @@ -54,6 +55,9 @@ private: rtl::OUString m_aProxyName; sal_Int32 m_nProxyPort; + // The server, according RFC7231 + // http://tools.ietf.org/html/rfc7231#section-7.4.2 + rtl::OUString m_aServerHeaderField; SerfConnection* m_pSerfConnection; serf_context_t* m_pSerfContext; @@ -66,12 +70,14 @@ private: DAVRequestEnvironment m_aEnv; -// static SerfLockStore m_aSerfLockStore; + static SerfLockStore m_aSerfLockStore; char* getHostinfo(); bool isSSLNeeded(); - SerfRequestProcessor* createReqProc( const rtl::OUString & inPath ); + SerfRequestProcessor* createReqProc( const rtl::OUString & inPath ); + + rtl::OUString composeCurrentUri( const rtl::OUString & inPath ); protected: virtual ~SerfSession(); @@ -258,6 +264,10 @@ public: sal_Bool isDomainMatch( rtl::OUString certHostName ); + const rtl::OUString & getServerHeaderField() { return m_aServerHeaderField; }; + + void setServerHeaderField( rtl::OUString aServerHeaderField ) { m_aServerHeaderField = aServerHeaderField; }; + private: friend class SerfLockStore; Modified: openoffice/trunk/main/ucb/source/ucp/webdav/SerfTypes.hxx URL: http://svn.apache.org/viewvc/openoffice/trunk/main/ucb/source/ucp/webdav/SerfTypes.hxx?rev=1705199&r1=1705198&r2=1705199&view=diff ============================================================================== --- openoffice/trunk/main/ucb/source/ucp/webdav/SerfTypes.hxx (original) +++ openoffice/trunk/main/ucb/source/ucp/webdav/SerfTypes.hxx Thu Sep 24 23:49:58 2015 @@ -25,13 +25,42 @@ #define INCLUDED_SERFTYPES_HXX #include <serf.h> +#include <com/sun/star/ucb/Lock.hpp> +#include "DAVTypes.hxx" +#include "DAVRequestEnvironment.hxx" + +using namespace com::sun::star; + +namespace http_dav_ucp +{ typedef serf_connection_t SerfConnection; -// TODO, figure out type of <SerfLock> -typedef int SerfLock; +class SerfLock +{ +private: + ucb::Lock mLock; + const rtl::OUString mResourceUri; + const rtl::OUString mPathStr; + // const DAVRequestEnvironment& mrRequestEnvironment; +public: + + SerfLock(const ucb::Lock inLock, rtl::OUString inUri, rtl::OUString inPath) + : mLock( inLock ) + , mResourceUri( inUri ) + , mPathStr( inPath ) + // , mrRequestEnvironment( rEnv ) + {}; + + void setLock(const ucb::Lock inLock) { mLock = inLock; }; + const ucb::Lock getLock() { return mLock; }; + const rtl::OUString getResourceUri() { return mResourceUri; }; + const rtl::OUString getResourcePath() { return mPathStr; }; + // const DAVRequestEnvironment& getRequestEnvironment() { return mrRequestEnvironment; }; +}; // TODO, check if we need it later on typedef struct { const char *nspace, *name; } SerfPropName; +}; #endif // INCLUDED_SERFTYPES_HXX Modified: openoffice/trunk/main/ucb/source/ucp/webdav/makefile.mk URL: http://svn.apache.org/viewvc/openoffice/trunk/main/ucb/source/ucp/webdav/makefile.mk?rev=1705199&r1=1705198&r2=1705199&view=diff ============================================================================== --- openoffice/trunk/main/ucb/source/ucp/webdav/makefile.mk (original) +++ openoffice/trunk/main/ucb/source/ucp/webdav/makefile.mk Thu Sep 24 23:49:58 2015 @@ -131,6 +131,10 @@ SLOFILES=\ $(SLO)$/SerfMkColReqProcImpl.obj \ $(SLO)$/SerfCopyReqProcImpl.obj \ $(SLO)$/SerfMoveReqProcImpl.obj \ + $(SLO)$/SerfLockReqProcImpl.obj \ + $(SLO)$/SerfLockRefreshProcImpl.obj \ + $(SLO)$/SerfUnlockProcImpl.obj \ + $(SLO)$/SerfLockStore.obj \ $(SLO)$/SerfSession.obj \ $(SLO)$/SerfCallbacks.obj \ $(SLO)$/SerfInputStream.obj \ @@ -148,6 +152,7 @@ SHL1IMPLIB=i$(TARGET) SHL1VERSIONMAP=$(SOLARENV)/src/component.map SHL1STDLIBS+=\ + $(TOOLSLIB) \ $(CPPUHELPERLIB) \ $(CPPULIB) \ $(SALLIB) \ Modified: openoffice/trunk/main/ucb/source/ucp/webdav/webdavcontent.cxx URL: http://svn.apache.org/viewvc/openoffice/trunk/main/ucb/source/ucp/webdav/webdavcontent.cxx?rev=1705199&r1=1705198&r2=1705199&view=diff ============================================================================== --- openoffice/trunk/main/ucb/source/ucp/webdav/webdavcontent.cxx (original) +++ openoffice/trunk/main/ucb/source/ucp/webdav/webdavcontent.cxx Thu Sep 24 23:49:58 2015 @@ -53,6 +53,7 @@ #include <com/sun/star/ucb/InsertCommandArgument.hpp> #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp> #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp> +#include <com/sun/star/ucb/InteractiveLockingLockNotAvailableException.hpp> #include <com/sun/star/ucb/InteractiveLockingLockedException.hpp> #include <com/sun/star/ucb/InteractiveLockingLockExpiredException.hpp> #include <com/sun/star/ucb/InteractiveLockingNotLockedException.hpp> @@ -84,6 +85,7 @@ #include "ContentProperties.hxx" #include "SerfUri.hxx" #include "UCBDeadPropertyValue.hxx" +#include <boost/current_function.hpp> using namespace com::sun::star; using namespace http_dav_ucp; @@ -728,23 +730,19 @@ uno::Any SAL_CALL Content::execute( post( aArg, Environment ); } else if ( aCommand.Name.equalsAsciiL( - RTL_CONSTASCII_STRINGPARAM( "lock" ) ) && - supportsExclusiveWriteLock( Environment ) ) + RTL_CONSTASCII_STRINGPARAM( "lock" ) ) ) { ////////////////////////////////////////////////////////////////// // lock ////////////////////////////////////////////////////////////////// - lock( Environment ); } else if ( aCommand.Name.equalsAsciiL( - RTL_CONSTASCII_STRINGPARAM( "unlock" ) ) && - supportsExclusiveWriteLock( Environment ) ) + RTL_CONSTASCII_STRINGPARAM( "unlock" ) ) ) { ////////////////////////////////////////////////////////////////// // unlock ////////////////////////////////////////////////////////////////// - unlock( Environment ); } else if ( aCommand.Name.equalsAsciiL( @@ -1454,7 +1452,8 @@ uno::Reference< sdbc::XRow > Content::ge if ( !bHasAll ) { - // Only DAV resources support PROPFIND + // Only DAV resources support PROPFIND, + // check already done above in the outer 'if' head std::vector< rtl::OUString > aPropNames; uno::Sequence< beans::Property > aProperties( @@ -1475,17 +1474,16 @@ uno::Reference< sdbc::XRow > Content::ge while ( it != end ) { - if ( *it == rName ) + if ( *it == rName ) { + //the failed property in cache is the same as the requested one + //add to the requested properties list + aProperties[ nProps ] = rProperties[ n ]; + nProps++; break; + } ++it; } - - if ( it == end ) - { - aProperties[ nProps ] = rProperties[ n ]; - nProps++; - } } aProperties.realloc( nProps ); @@ -3013,6 +3011,23 @@ void Content::lock( const uno::Reference< ucb::XCommandEnvironment >& Environment ) throw( uno::Exception ) { + // i126305 TODO: add a check to see if this is really a DAV resource ? + // currently if the lock is not supported + // we got an error from the server that should be checked by the client (framework) + rtl::OUString aURL; + if ( m_bTransient ) + { + aURL = getParentURL(); + if ( aURL.lastIndexOf( '/' ) != ( aURL.getLength() - 1 ) ) + aURL += rtl::OUString::createFromAscii( "/" ); + + aURL += m_aEscapedTitle; + } + else + { + aURL = m_xIdentifier->getContentIdentifier(); + } + try { std::auto_ptr< DAVResourceAccess > xResAccess; @@ -3021,16 +3036,33 @@ void Content::lock( xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) ); } + // TODO i126305 to discuss: + // the owner string is the string that will be returned when the lock will be + // interrogated, via lockdiscovery. + // It should tell a user who is holding the document lock. + // The string currently set as owner is the one most useful now, telling what application locked the resource. + // May be it would be better put here something better ? + // Some string be added to office config? Or name of the user there? Or a document property user selectable? + // in case of adding it in config, the lock command should be added a string for the owner, and this + // will be in turn filled in by the framework (e.g. the ucb client). + // Of course in case of a configuration item, the string should be checked against internationalization + // and how to manage it in webdav protocol, this was not checked while solving i126305. uno::Any aOwnerAny; aOwnerAny - <<= rtl::OUString::createFromAscii( "http://ucb.openoffice.org" ); + <<= rtl::OUString::createFromAscii( "Apache OpenOffice - https://www.openoffice.org" ); + // TODO i126305 to discuss: + // on some webdav server, the 180 time formerly used appears to be too long, + // in this case, in response to a lock refresh operation we receive an error + // as 'Connection reset by peer', meaning the session was timed out by the other end. + // For now drop the defaul time to 120 seconds, seems better. + // In the future, another way of keeping the connection alive should be devised. ucb::Lock aLock( ucb::LockScope_EXCLUSIVE, ucb::LockType_WRITE, ucb::LockDepth_ZERO, aOwnerAny, - 180, // lock timeout in secs + 120, // lock timeout in secs //-1, // infinite lock uno::Sequence< ::rtl::OUString >() ); @@ -3043,6 +3075,44 @@ void Content::lock( } catch ( DAVException const & e ) { + switch(e.getStatus()) + { + case SC_LOCKED: + { + rtl::OUString aOwner( getLockOwner( Environment ) ); + + throw(ucb::InteractiveLockingLockedException( + rtl::OUString::createFromAscii( "Locked!" ), + static_cast< cppu::OWeakObject * >( this ), + task::InteractionClassification_ERROR, + aURL, + e.getExtendedError(), + sal_False, + aOwner )); + } + break; + case SC_METHOD_NOT_ALLOWED: + // this it's not always received, but the RFC4918 (which supersed RFC2518) + // tells about this in: + // http://tools.ietf.org/html/rfc4918#appendix-D.1 + // throw exception, will be interpreted by the lock requester (framework) + // it is actually a info, not an error + throw ucb::InteractiveLockingLockNotAvailableException( e.getData(), + static_cast< cppu::OWeakObject * >( this ), + task::InteractionClassification_INFO, + aURL, + e.getExtendedError() ); + break; + //i126305 TODO + //see http://tools.ietf.org/html/rfc4918#section-9.10.6 + //not sure how to handle them, for the time being a dialog box is shown, + //the client (framework) should manage it + case SC_CONFLICT: + case SC_PRECONDITION_FAILED: + default: + //fallthrou + ; + } cancelCommandExecution( e, Environment, sal_False ); // Unreachable } @@ -3070,8 +3140,15 @@ void Content::unlock( } catch ( DAVException const & e ) { - cancelCommandExecution( e, Environment, sal_False ); + //i126305 TODO need to rise an exception of the right type ? + //meaning that the lock can not be released, since there is no such + //exception we use ucb::InteractiveNetworkReadException + throw ucb::InteractiveNetworkReadException( e.getData(), + static_cast< cppu::OWeakObject * >( this ), + task::InteractionClassification_INFO, + e.getData() );//perhaps a more better should be used ? // Unreachable + cancelCommandExecution( e, Environment, sal_False ); } } @@ -3292,7 +3369,9 @@ uno::Any Content::MapDAVException( const static_cast< cppu::OWeakObject * >( this ), task::InteractionClassification_ERROR, aURL, - sal_False ); // not SelfOwned + e.getExtendedError(), + sal_False, // not SelfOwned + rtl::OUString() ); #else { uno::Sequence< uno::Any > aArgs( 1 ); @@ -3319,7 +3398,9 @@ uno::Any Content::MapDAVException( const static_cast< cppu::OWeakObject * >( this ), task::InteractionClassification_ERROR, aURL, - sal_True ); // SelfOwned + e.getExtendedError(), + sal_True, // SelfOwned + e.getOwner() ); break; case DAVException::DAV_NOT_LOCKED: @@ -3328,7 +3409,8 @@ uno::Any Content::MapDAVException( const rtl::OUString::createFromAscii( "Not locked!" ), static_cast< cppu::OWeakObject * >( this ), task::InteractionClassification_ERROR, - aURL ); + aURL, + rtl::OUString() );//no extended info here break; case DAVException::DAV_LOCK_EXPIRED: @@ -3337,13 +3419,20 @@ uno::Any Content::MapDAVException( const rtl::OUString::createFromAscii( "Lock expired!" ), static_cast< cppu::OWeakObject * >( this ), task::InteractionClassification_ERROR, - aURL ); + aURL, + rtl::OUString() );//no extended info here break; default: + rtl::OUStringBuffer buf( 512 ); + buf.appendAscii( BOOST_CURRENT_FUNCTION ); + buf.appendAscii( ":" ); + buf.append( (sal_Int32) __LINE__ ); + buf.appendAscii( " - Unknown DAV error: " ); + buf.append( (sal_Int32) e.getError() ); aException <<= ucb::InteractiveNetworkGeneralException( - rtl::OUString(), + rtl::OUString(buf.makeStringAndClear()), static_cast< cppu::OWeakObject * >( this ), task::InteractionClassification_ERROR ); break; @@ -3450,7 +3539,7 @@ const Content::ResourceType & Content::g // this is a DAV resource. std::vector< DAVResource > resources; std::vector< rtl::OUString > aPropNames; - uno::Sequence< beans::Property > aProperties( 5 ); + uno::Sequence< beans::Property > aProperties( 6 ); aProperties[ 0 ].Name = rtl::OUString::createFromAscii( "IsFolder" ); aProperties[ 1 ].Name @@ -3461,6 +3550,9 @@ const Content::ResourceType & Content::g = rtl::OUString::createFromAscii( "MediaType" ); aProperties[ 4 ].Name = DAVProperties::SUPPORTEDLOCK; + //we will need this to check for existing locks + aProperties[ 5 ].Name + = DAVProperties::LOCKDISCOVERY; ContentProperties::UCBNamesToDAVNames( aProperties, aPropNames ); @@ -3469,8 +3561,13 @@ const Content::ResourceType & Content::g DAVZERO, aPropNames, resources, xEnv ); // TODO - is this really only one? + // only one resource is received, see at: + // WebDAVResponseParser::endElement() + // case WebDAVName_response + //in file: ucb/source/ucp/webdav/webdavresponseparser.cxx: if ( resources.size() == 1 ) { + // there is a single resource m_xCachedProps.reset( new CachableContentProperties( resources[ 0 ] ) ); m_xCachedProps->containsAllNames( @@ -3507,3 +3604,38 @@ const Content::ResourceType & Content::g { return getResourceType( xEnv, m_xResAccess ); } + +rtl::OUString Content::getLockOwner( const uno::Reference< ucb::XCommandEnvironment >& Environment ) +{ + rtl::OUString aOwner; + try + { + //DAVProperties::LOCKDISCOVERY is not cached, need to get it from the server + uno::Sequence< beans::Property > aProperties( 1 ); + aProperties[ 0 ].Name = DAVProperties::LOCKDISCOVERY; + aProperties[ 0 ].Handle = -1; + + uno::Reference< sdbc::XRow > xRow( getPropertyValues( aProperties, Environment ) ); + + sal_Int32 nCount = aProperties.getLength(); + uno::Sequence< uno::Any > aValues( nCount ); + uno::Any* pValues = aValues.getArray(); + pValues[ 0 ] = xRow->getObject( 1, uno::Reference< container::XNameAccess >() ); + + uno::Sequence< ::com::sun::star::ucb::Lock > aLocks; + + if(aValues.getConstArray()[ 0 ] >>= aLocks) + if(aLocks.getLength() > 0) + { + ucb::Lock aLock = aLocks[0]; + aLock.Owner >>= aOwner; + OSL_TRACE("Content::getLockOwner - aOwner: '%s', <<<<<<<<<<<<<<<<<<<<<<<<<<<<<", + rtl::OUStringToOString(aOwner, RTL_TEXTENCODING_UTF8).getStr()); + + } + } + catch ( uno::Exception&) + { } + + return aOwner; +}