--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/remotestoragefw/webdavaccessplugin/src/rsfwdavsession.cpp Thu Dec 17 09:07:59 2009 +0200
@@ -0,0 +1,1322 @@
+/*
+* Copyright (c) 2002-2004 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: API for WebDAV operations
+ *
+*/
+
+
+// INCLUDE FILES
+#include <httpstringconstants.h>
+#include <http/rhttpheaders.h>
+#include <escapeutils.h>
+#include <xml/matchdata.h>
+
+#include "rsfwdavsession.h"
+#include "rsfwdavtransaction.h"
+#include "rsfwconnectionmanager.h"
+#include "rsfwpropfindparser.h"
+#include "rsfwlockqueryparser.h"
+#include "mdebug.h"
+
+// CONSTANTS
+// characters that will be encoded in the url
+_LIT8(KSpecials8, " \"<>#%{}|\\^~[]`");
+
+// ============================ MEMBER FUNCTIONS ==============================
+CRsfwDavSession* CRsfwDavSession::NewL(
+ MRsfwDavResponseObserver* aWebDavResponseObserver,
+ MRsfwConnectionObserver* aRsfwConnectionObserver)
+ {
+ CRsfwDavSession* self = new (ELeave) CRsfwDavSession;
+ CleanupStack::PushL(self);
+ self->ConstructL(aWebDavResponseObserver, aRsfwConnectionObserver);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+void CRsfwDavSession::ConstructL(
+ MRsfwDavResponseObserver* aWebDavResponseObserver,
+ MRsfwConnectionObserver* aRsfwConnectionObserver)
+ {
+ DEBUGSTRING(("DavSess: ConstructL: enter"));
+ User::LeaveIfError(iFs.Connect());
+ iWebDavResponseObserver = aWebDavResponseObserver;
+ iRsfwConnectionObserver = aRsfwConnectionObserver;
+
+ // Create classes needed for parsing PropFind and Lock request replies
+ // Creating these later seems to cause emulator hang-ups.
+ // If the problem does not exist in the real device we may want to
+ // delay especially Lock parser creation as locking may not be used at all.
+ Xml::CMatchData* matchData = Xml::CMatchData::NewLC();
+ matchData->SetMimeTypeL(KTextXml);
+ // Select libxml2 parsesr
+ matchData->SetVariantL(_L8("libxml2"));
+ // Select Symbian XML Parser (=Expat)
+// matchData->SetVariantL(_L8("Symbian"));
+ iPropFindParserImpl = CRsfwPropFindParser::NewL();
+ iPropFindParser = Xml::CParser::NewL(*matchData, *iPropFindParserImpl);
+ iLockQueryParserImpl = CRsfwLockQueryParser::NewL();
+ iLockQueryParser = Xml::CParser::NewL(*matchData, *iLockQueryParserImpl);
+ CleanupStack::PopAndDestroy(matchData);
+
+ // Open the RHTTPSession
+ iHttpSession.OpenL();
+ iHttpSession.FilterCollection().RemoveFilter(
+ iHttpSession.StringPool().StringF( HTTP::EAuthentication, RHTTPSession::GetTable() ));
+ // Install this class as the callback for authentication requests:
+ // it will take care of basic/digest auth, SSL
+ InstallAuthenticationL(iHttpSession);
+ DEBUGSTRING(("auth filter installed"));
+ }
+
+CRsfwDavSession::~CRsfwDavSession()
+ {
+ DEBUGSTRING(("CRsfwDavSession::~CRsfwDavSession"));
+ delete iPropFindParser;
+ delete iPropFindParserImpl;
+ delete iLockQueryParser;
+ delete iLockQueryParserImpl;
+ delete iEncodedHost;
+ if (iUserName)
+ {
+ delete iUserName;
+ }
+ if (iPassword)
+ {
+ delete iPassword;
+ }
+ iHttpSession.Close();
+ delete iRsfwConnectionManager;
+ iFs.Close();
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::SetConnected
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavSession::SetConnected(TBool aConnected)
+ {
+ iConnected = aConnected;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::SetWebDavSupportClass
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavSession::SetWebDavSupportClass(TInt aWebDavSupportClass)
+ {
+ iWebDavSupportClass = aWebDavSupportClass;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::WebDavSupportClass
+// ----------------------------------------------------------------------------
+//
+TInt CRsfwDavSession::WebDavSupportClass()
+ {
+ return iWebDavSupportClass;
+ }
+
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::OpenL
+// After calling this function, use options query
+// to trigger TCP level connection.
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavSession::OpenL(const TDesC& aUri,
+ TInt aPort,
+ const TDesC& aUserName,
+ const TDesC& aPassword,
+ const TDesC& aAuxData)
+ {
+ // Store connection parameters
+ iHost.Zero();
+ iDavRoot.Zero();
+
+ // Here we add the port using a simple approach:
+ // it needs to go after http://name/
+ TInt slashCnt = 0;
+ TInt cnt = 0;
+ while (cnt < aUri.Length())
+ {
+ TChar ch = aUri[cnt++];
+ if (ch == '/')
+ {
+ slashCnt++;
+ if (slashCnt == 3)
+ {
+ iHost.Append(':');
+ iHost.AppendNum(aPort);
+ // At this point we know that
+ // the remainder of the uri is the root directory
+ }
+ }
+
+ if (slashCnt > 2)
+ {
+ iDavRoot.Append(ch);
+ }
+ else
+ {
+ iHost.Append(ch);
+ }
+ }
+ // We elso need an encoded form of the host part
+ iEncodedHost = EncodeL(iHost.Right(iHost.Length() - KProtocolPrefix));
+
+ // iDavRoot must be a directory, and thus should end with a slash
+ Slashify(iDavRoot);
+
+ // Make the pair
+ iHostRoot.Copy(iHost);
+ iHostRoot.Append(iDavRoot);
+
+ // Assume that the parameters are constant and stable across the session
+ iUserName = EncodeL(aUserName);
+ iPassword = EncodeL(aPassword);
+ iAuxData.Copy(aAuxData);
+
+ DEBUGSTRING16(("connecting to host='%S', port=%d, root='%S', data=%S",
+ &iHost,
+ aPort,
+ &iDavRoot,
+ &iAuxData));
+
+ if (iAuxData.Length() == 0)
+ {
+ // in case of empty access point info, set it to '?' (ask user)
+ _LIT(KAskUser, "?");
+ iAuxData.Copy(KAskUser);
+ }
+
+ if (!iRsfwConnectionManager)
+ {
+ iRsfwConnectionManager =
+ CRsfwConnectionManager::NewL(iRsfwConnectionObserver);
+ iRsfwConnectionManager->UseIapL(aAuxData);
+ }
+
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::OptionsL
+// ----------------------------------------------------------------------------
+//
+CRsfwDavTransaction* CRsfwDavSession::OptionsL()
+ {
+ TPtrC null;
+ TUriParser8 uriParser;
+ HBufC8* uri = BuildUriLC(null, EFalse, &uriParser);
+
+ DEBUGSTRING8(("OPTIONS '%S'", &uriParser.UriDes()));
+
+ // Establish a link-layer connection
+ if (iRsfwConnectionManager)
+ {
+ SetupConnectionL();
+ }
+
+ RStringPool stringPool = StringPool();
+
+ // Introducing the webdav headers for the propfind
+ RStringF mOptions = stringPool.OpenFStringL(KWebDavOptions);
+ CleanupClosePushL(mOptions);
+ CRsfwDavTransaction* webDavTransaction =
+ CRsfwDavTransaction::NewL(this,
+ EWebDavOpOptions,
+ uriParser,
+ mOptions,
+ NextWebDavTransactionId());
+ CleanupStack::PopAndDestroy(); // mOptions
+ CleanupStack::PushL(webDavTransaction);
+
+ RHTTPHeaders hdr = webDavTransaction->
+ HttpTransaction().Request().GetHeaderCollection();
+
+ SetBasicHeadersL(hdr, uriParser, ETrue);
+
+ CleanupStack::Pop(2); //webDavTransaction, uri
+ delete uri;
+ return webDavTransaction;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::PropFindL
+// Implements WebDAV PROPFIND method.
+// Parameters: Name of the directory or file
+// CRsfwDirEnt pointer array to be filled with directory metadata
+// PROPFIND depth
+// aIsDir, is this directory or file,
+// some extra checks are made based on this...
+// ----------------------------------------------------------------------------
+//
+CRsfwDavTransaction* CRsfwDavSession::PropFindL(const TDesC &aPath,
+ TInt aDepth,
+ TBool aIsDir,
+ RPointerArray<CRsfwDirEnt>& aDirEnts)
+ {
+ if (!IsConnected())
+ {
+ User::Leave(KErrNotReady);
+ }
+
+ TUriParser8 uriParser;
+ HBufC8* uri = BuildUriLC(aPath, aIsDir, &uriParser);
+
+ DEBUGSTRING8(("PROPFIND '%S'", &uriParser.UriDes()));
+
+ // This function is used from several places
+ TWebDavOp op;
+ if (aDepth == 1)
+ {
+ op = EWebDavOpPropFindMulti;
+ }
+ else // (aDepth == 0)
+ {
+ op = EWebDavOpPropFindSingle;
+ }
+
+ RStringPool stringPool = StringPool();
+ RStringF mPropFind = stringPool.OpenFStringL(KWebDavPropFind);
+ CleanupClosePushL(mPropFind);
+ CRsfwDavTransaction* webDavTransaction =
+ CRsfwDavTransaction::NewL(this,
+ op,
+ uriParser,
+ mPropFind,
+ NextWebDavTransactionId());
+ CleanupStack::PopAndDestroy(); // mPropFind
+ CleanupStack::PushL(webDavTransaction);
+
+ RHTTPHeaders hdr = webDavTransaction->
+ HttpTransaction().Request().GetHeaderCollection();
+
+ // Add headers appropriate to all methods
+ SetBasicHeadersL(hdr, uriParser, ETrue);
+
+ SetHeaderL(hdr, HTTP::EContentType, KTextXml);
+
+ // Assumes that the target uri has been cached in an earlier connect
+ SetDepthHeaderL(hdr, aDepth);
+
+ // XML body
+ HBufC8* requestBodyBuffer = HBufC8::NewL(KDefaultSubmitSize);
+ TPtr8 requestBodyBufferPtr = requestBodyBuffer->Des();
+
+ // To make things at least little bit faster,
+ // let's try to get "minimal" set
+ // Maybe useful one day:
+ // - <D:getcontentlanguage/>
+ // - <D:creationdate/>
+ // Apache mod_dav 1.0.3 doesn't support:
+ // - <D:displayname/>
+ _LIT8(KPropFindRequestBody, "\
+<?xml version=\"1.0\"?>\
+<propfind xmlns=\"DAV:\">\
+<prop>\
+<getcontenttype/>\
+<getlastmodified/>\
+<getcontentlength/>\
+<resourcetype/>\
+<getetag/>\
+</prop>\
+</propfind>\
+");
+ requestBodyBufferPtr.Append(KPropFindRequestBody);
+ webDavTransaction->SetBodyData(requestBodyBuffer);
+
+ webDavTransaction->SetPropFindDirEntryArray(aDirEnts);
+ // We must remember the work directory,
+ // as we don't want to list that when building directory listing.
+ HBufC* propFindPath = HBufC::NewL(iHostRoot.Length() +
+ KMaxPath +
+ 1);
+ TPtr propFindPathPtr = propFindPath->Des();
+ propFindPathPtr.Copy(iDavRoot);
+ propFindPathPtr.Append(aPath);
+ // The whole path must end with a slash
+ Slashify(propFindPathPtr);
+ // Before comparing the path from the server is decoded,
+ // so we can compare against the original 16-bit string.
+ webDavTransaction->SetPropFindPath(propFindPath);
+ CleanupStack::Pop(2); // webdavtransaction, uri
+ delete uri;
+ return webDavTransaction;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::GetL
+// ----------------------------------------------------------------------------
+//
+CRsfwDavTransaction* CRsfwDavSession::GetL(const TDesC& aSrcPath,
+ const TDesC& aDstPath,
+ TInt aOffset,
+ TInt* aLength,
+ TUint aFlags)
+ {
+ // Basically just a HTTP get with some local processing
+ if (!IsConnected())
+ {
+ User::Leave(KErrNotReady);
+ }
+
+ TUriParser8 uriParser;
+ HBufC8* uri = BuildUriLC(aSrcPath, EFalse, &uriParser);
+
+#ifdef _DEBUG
+ {
+ TInt length;
+ if (aLength)
+ {
+ length = *aLength;
+ }
+ else
+ {
+ length = 0;
+ }
+ DEBUGSTRING8(("GET '%S' (off=%d, len=%d)",
+ &uriParser.UriDes(),
+ aOffset,
+ length));
+ }
+#endif // DEBUG
+
+ // Introducing the webdav headers for GET
+ RStringPool stringPool = StringPool();
+ RStringF mGet = stringPool.StringF(HTTP::EGET,
+ RHTTPSession::GetTable());
+ CRsfwDavTransaction* webDavTransaction =
+ CRsfwDavTransaction::NewL(this,
+ EWebDavOpGet,
+ uriParser,
+ mGet,
+ NextWebDavTransactionId());
+ CleanupStack::PushL(webDavTransaction);
+
+ // Not sure if this is needed: we are setting conditions
+ // which mod_dav never gets, cos this is a GET..
+ RHTTPHeaders hdr =
+ webDavTransaction->HttpTransaction().Request().GetHeaderCollection();
+
+ // Add headers appropriate to all methods
+ SetBasicHeadersL(hdr, uriParser, ETrue);
+
+ if (aLength && (*aLength > 0)) // partial get
+ {
+ TBuf8<KMaxFieldValueLength> rangeHeader;
+ _LIT8(KBytesEquals, "bytes=");
+ rangeHeader.Append(KBytesEquals);
+ rangeHeader.AppendNum(aOffset);
+ rangeHeader.Append('-');
+ rangeHeader.AppendNum(aOffset + *aLength - 1);
+ SetHeaderL(hdr, HTTP::ERange, rangeHeader);
+ }
+
+ webDavTransaction->SetBodyFileL(aDstPath, aOffset, aLength, aFlags);
+ CleanupStack::Pop(webDavTransaction);
+ CleanupStack::PopAndDestroy(uri);
+ return webDavTransaction;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::PutL
+// This amounts to a PUT sending the src data to the destination.
+// Expects that the aSrcPath param is relative to iDavRoot.
+// If aSrcPath is empty, an empty file will be created.
+// ----------------------------------------------------------------------------
+//
+CRsfwDavTransaction* CRsfwDavSession::PutL(const TDesC& aSrcPath,
+ const TDesC& aDstPath,
+ const TDesC8& aMimeType,
+ TInt aOffset,
+ TInt aLength,
+ TInt aTotalLength,
+ TBool aUseContentRange,
+ const TDesC8* aLockToken)
+ {
+ if (!IsConnected())
+ {
+ User::Leave(KErrNotReady);
+ }
+
+ TUriParser8 uriParser;
+ HBufC8* uri = BuildUriLC(aDstPath, EFalse, &uriParser);
+
+ DEBUGSTRING8(("PUT '%S'", &uriParser.UriDes()));
+
+ RStringPool stringPool = StringPool();
+ RStringF mPut = stringPool.OpenFStringL(KWebDavPut);
+ CleanupClosePushL(mPut);
+ CRsfwDavTransaction* webDavTransaction =
+ CRsfwDavTransaction::NewL(this,
+ EWebDavOpPut,
+ uriParser,
+ mPut,
+ NextWebDavTransactionId());
+ CleanupStack::PopAndDestroy(); // mPut
+ CleanupStack::PushL(webDavTransaction);
+
+ RHTTPHeaders hdr =
+ webDavTransaction->HttpTransaction().Request().GetHeaderCollection();
+
+ // Add headers appropriate to all methods
+ SetBasicHeadersL(hdr, uriParser, ETrue);
+ SetHeaderL(hdr, HTTP::EContentType, aMimeType);
+
+ if (aLength > 0) // partial put
+ {
+ if (aUseContentRange)
+ {
+ TBuf8<KMaxFieldValueLength> rangeHeader;
+ _LIT8(KBytes, "bytes ");
+ rangeHeader.Append(KBytes);
+ rangeHeader.AppendNum(aOffset);
+ rangeHeader.Append('-');
+ rangeHeader.AppendNum(aOffset + aLength - 1);
+ rangeHeader.Append('/');
+ if (aTotalLength == 0)
+ {
+ // The asterisk "*" character means that
+ // the instance-length is unknown at the time when
+ // the message was generated.
+ rangeHeader.Append('*');
+ }
+ else
+ {
+ rangeHeader.AppendNum(aTotalLength);
+ }
+ SetHeaderL(hdr, HTTP::EContentRange, rangeHeader);
+ }
+ else
+ {
+ // server doesn't support Content-Range
+ // Leave with KrrNotSupported
+ // *aLength = aTotalLength;
+ }
+ }
+
+ if (aLockToken)
+ {
+ SetLockTokenHeaderL(hdr, uri, aLockToken, ETrue);
+ }
+
+ webDavTransaction->SetBodyFileL(aSrcPath, aOffset, &aLength, 0);
+ CleanupStack::Pop(webDavTransaction);
+ CleanupStack::PopAndDestroy(uri);
+ return webDavTransaction;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::DeleteL
+// ----------------------------------------------------------------------------
+//
+CRsfwDavTransaction* CRsfwDavSession::DeleteL(const TDesC& aPath,
+ TBool aIsDir,
+ const TDesC8* aLockToken)
+ {
+ // Needs to take locking into account
+ if (!IsConnected())
+ {
+ User::Leave(KErrNotReady);
+ }
+
+ TUriParser8 uriParser;
+ HBufC8* uri = BuildUriLC(aPath, aIsDir, &uriParser);
+
+ DEBUGSTRING8(("DELETE '%S'", &uriParser.UriDes()));
+
+ RStringPool stringPool = StringPool();
+ RStringF mDelete = stringPool.OpenFStringL(KWebDavDelete);
+ CleanupClosePushL(mDelete);
+ CRsfwDavTransaction* webDavTransaction =
+ CRsfwDavTransaction::NewL(this,
+ EWebDavOpDelete,
+ uriParser,
+ mDelete,
+ NextWebDavTransactionId());
+ CleanupStack::PopAndDestroy(); // mDelete
+ CleanupStack::PushL(webDavTransaction);
+
+ // need to add a special dir on the i
+ RHTTPHeaders hdr =
+ webDavTransaction->HttpTransaction().Request().GetHeaderCollection();
+ // Add headers appropriate to all methods
+ SetBasicHeadersL(hdr, uriParser, ETrue);
+
+ if (aLockToken)
+ {
+ SetLockTokenHeaderL(hdr, uri, aLockToken, ETrue);
+ }
+
+ CleanupStack::Pop(webDavTransaction);
+ CleanupStack::PopAndDestroy(uri);
+ return webDavTransaction;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::MkDirL
+// ----------------------------------------------------------------------------
+//
+CRsfwDavTransaction* CRsfwDavSession::MkDirL(const TDesC& aPath)
+ {
+ // Executes a MKCOL with the specified name
+ if (!IsConnected())
+ {
+ User::Leave(KErrNotReady);
+ }
+
+ TUriParser8 uriParser;
+ HBufC8* uri = BuildUriLC(aPath, ETrue, &uriParser);
+
+ DEBUGSTRING8(("MKCOL '%S'", &uriParser.UriDes()));
+
+ RStringPool stringPool = StringPool();
+ RStringF mMkCol = stringPool.OpenFStringL(KWebDavMkCol);
+ CleanupClosePushL(mMkCol);
+ CRsfwDavTransaction* webDavTransaction =
+ CRsfwDavTransaction::NewL(this,
+ EWebDavOpMkCol,
+ uriParser,
+ mMkCol,
+ NextWebDavTransactionId());
+ CleanupStack::PopAndDestroy(1); // mMkCol
+ CleanupStack::PushL(webDavTransaction);
+
+ // Neeed to add a special dir on the i
+ RHTTPHeaders hdr =
+ webDavTransaction->HttpTransaction().Request().GetHeaderCollection();
+
+ // Add headers appropriate to all methods
+ SetBasicHeadersL(hdr, uriParser, ETrue);
+
+ CleanupStack::Pop(2); // webDavTransaction, uri
+ delete uri;
+ return webDavTransaction;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::MoveL
+// ----------------------------------------------------------------------------
+//
+CRsfwDavTransaction* CRsfwDavSession::MoveL(const TDesC& aOldPath,
+ const TDesC& aNewPath,
+ TBool aOverwrite,
+ const TDesC8* aSrcLockToken,
+ const TDesC8* aDstLockToken)
+ {
+ if (!IsConnected())
+ {
+ User::Leave(KErrNotReady);
+ }
+
+ TUriParser8 uriParserNew;
+ HBufC8* uriNew = BuildUriLC(aNewPath, EFalse, &uriParserNew);
+ TUriParser8 uriParserOld;
+ HBufC8* uriOld = BuildUriLC(aOldPath, EFalse, &uriParserOld);
+
+ DEBUGSTRING8(("MOVE '%S' to '%S'",
+ &uriParserOld.UriDes(),
+ &uriParserNew.UriDes()));
+
+ RStringPool stringPool = StringPool();
+ RStringF mMove = stringPool.OpenFStringL(KWebDavMove);
+ CleanupClosePushL(mMove);
+ CRsfwDavTransaction* webDavTransaction =
+ CRsfwDavTransaction::NewL(this,
+ EWebDavOpMove,
+ uriParserOld,
+ mMove,
+ NextWebDavTransactionId());
+ CleanupStack::PopAndDestroy(); // mMove
+ CleanupStack::PushL(webDavTransaction);
+
+ RHTTPHeaders hdr =
+ webDavTransaction->HttpTransaction().Request().GetHeaderCollection();
+
+ // Add headers appropriate to all methods
+ SetBasicHeadersL(hdr, uriParserOld, ETrue);
+
+ if (aSrcLockToken)
+ {
+ SetLockTokenHeaderL(hdr, uriOld, aSrcLockToken, ETrue);
+ }
+
+
+ if (aDstLockToken)
+ {
+ SetLockTokenHeaderL(hdr, uriNew, aDstLockToken, ETrue);
+ }
+
+ SetHeaderL(hdr, KWebDavDest, *uriNew);
+ if (aOverwrite)
+ {
+ SetHeaderL(hdr, KWebDavOverwrite, KWebDavOverwriteY);
+ }
+ else
+ {
+ SetHeaderL(hdr, KWebDavOverwrite, KWebDavOverwriteN);
+ }
+
+ CleanupStack::Pop(webDavTransaction);
+ CleanupStack::PopAndDestroy(2, uriNew); // uriOld, uriNew
+ return webDavTransaction;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::LockL
+// ----------------------------------------------------------------------------
+//
+CRsfwDavTransaction* CRsfwDavSession::LockL(const TDesC& aPath,
+ TUint aFlags,
+ TUint aTimeout,
+ CRsfwDavFileInfo** aDavFileInfo)
+ {
+ // Opens LOCK transaction
+ if (!IsConnected())
+ {
+ User::Leave(KErrNotReady);
+ }
+
+ TUriParser8 uriParser;
+ HBufC8* uri = BuildUriLC(aPath, EFalse, &uriParser);
+
+ DEBUGSTRING8(("LOCK '%S' (%d seconds)", &uriParser.UriDes(), aTimeout));
+
+ RStringPool stringPool = StringPool();
+ RStringF mLock = stringPool.OpenFStringL(KWebDavLock);
+ CleanupClosePushL(mLock);
+ CRsfwDavTransaction* webDavTransaction =
+ CRsfwDavTransaction::NewL(this,
+ EWebDavOpLock,
+ uriParser,
+ mLock,
+ NextWebDavTransactionId());
+ CleanupStack::PopAndDestroy(&mLock);
+ CleanupStack::PushL(webDavTransaction);
+
+ // headers
+ RHTTPHeaders hdr =
+ webDavTransaction->HttpTransaction().Request().GetHeaderCollection();
+
+ // Add headers appropriate to all methods
+ SetBasicHeadersL(hdr, uriParser, ETrue);
+
+ SetHeaderL(hdr, HTTP::EContentType, KTextXml);
+
+ HBufC8* timeoutBuffer = HBufC8::NewLC(KMaxFieldValueLength);
+ TPtr8 timeoutBufferPtr = timeoutBuffer->Des();
+ timeoutBufferPtr.Append(KSecondDash);
+ if (aTimeout != 0)
+ {
+ timeoutBufferPtr.AppendNum(aTimeout);
+ }
+ SetHeaderL(hdr, KWebDavTimeout, timeoutBufferPtr);
+ CleanupStack::PopAndDestroy(timeoutBuffer);
+
+ // XML body
+ HBufC8* requestBodyBuffer = HBufC8::NewL(KDefaultSubmitSize);
+ TPtr8 requestBodyBufferPtr = requestBodyBuffer->Des();
+
+ // Note: locktype "write" is currently the only legal value
+ _LIT8(KLockHeaderFormat, "\
+<?xml version=\"1.0\" encoding=\"utf-8\" ?>\
+<D:lockinfo xmlns:D=\"DAV:\">\
+<D:lockscope><D:%S/></D:lockscope>\
+<D:locktype><D:write/></D:locktype>\
+<D:owner xmlns:x=\"http://www.webdav.org/\">\
+<x:lock-user>%S</x:lock-user>\
+<x:created-by>%S</x:created-by>\
+</D:owner>\
+</D:lockinfo>");
+
+ _LIT8(KLockScopeShared, "shared");
+ _LIT8(KLockScopeExclusive, "exclusive");
+ TPtrC8 lockScope;
+ if (aFlags & EFileShareAny)
+ {
+ lockScope.Set(KLockScopeShared);
+ }
+ else
+ {
+ lockScope.Set(KLockScopeExclusive);
+ }
+
+ requestBodyBufferPtr.Format(KLockHeaderFormat, &lockScope, iUserName, iUserName);
+ webDavTransaction->SetBodyData(requestBodyBuffer);
+
+ HBufC* fileInfoPath = BuildFullPathLC(aPath, EFalse);
+ webDavTransaction->SetDavFileInfoL(aDavFileInfo, *fileInfoPath);
+ CleanupStack::PopAndDestroy(fileInfoPath);
+ CleanupStack::Pop(webDavTransaction);
+ CleanupStack::PopAndDestroy(uri);
+ return webDavTransaction;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::UnlockL
+// ----------------------------------------------------------------------------
+//
+CRsfwDavTransaction* CRsfwDavSession::UnlockL(const TDesC& aPath,
+ const TDesC8* aLockToken)
+ {
+ // Opens LOCK transaction
+ if (!IsConnected())
+ {
+ User::Leave(KErrNotReady);
+ }
+
+ if (iWebDavSupportClass < KDavVersionTwo)
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ TUriParser8 uriParser;
+ HBufC8* uri = BuildUriLC(aPath, EFalse, &uriParser);
+
+ DEBUGSTRING8(("UNLOCK '%S'", &uriParser.UriDes()));
+
+ RStringPool stringPool = StringPool();
+ RStringF mUnlock = stringPool.OpenFStringL(KWebDavUnlock);
+ CleanupClosePushL(mUnlock);
+ CRsfwDavTransaction* webDavTransaction =
+ CRsfwDavTransaction::NewL(this,
+ EWebDavOpUnlock,
+ uriParser,
+ mUnlock,
+ NextWebDavTransactionId());
+ CleanupStack::PopAndDestroy(); // mUnlock
+ CleanupStack::PushL(webDavTransaction);
+
+ RHTTPHeaders hdr =
+ webDavTransaction->HttpTransaction().Request().GetHeaderCollection();
+
+ // Add headers appropriate to all methods
+ SetBasicHeadersL(hdr, uriParser, ETrue);
+
+ HBufC8* lockToken = HBufC8::NewLC(aLockToken->Length() +
+ KLockTokenOverhead);
+ TPtr8 lockTokenPtr = lockToken->Des();
+ lockTokenPtr.Append('<');
+ lockTokenPtr.Append(*aLockToken);
+ lockTokenPtr.Append('>');
+ SetHeaderL(hdr, KWedDavLockToken, lockTokenPtr);
+ CleanupStack::PopAndDestroy(lockToken);
+
+ CleanupStack::Pop(2); // webdavtransaction , uri
+ delete uri;
+ return webDavTransaction;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::RefreshLockL
+// ----------------------------------------------------------------------------
+//
+CRsfwDavTransaction* CRsfwDavSession::RefreshLockL(const TDesC& aPath,
+ TUint aTimeout,
+ const TDesC8* aLockToken,
+ CRsfwDavFileInfo** aDavFileInfo)
+ {
+ // Opens LOCK transaction
+ if (!IsConnected())
+ {
+ User::Leave(KErrNotReady);
+ }
+
+ if (iWebDavSupportClass < KDavVersionTwo)
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ TUriParser8 uriParser;
+ HBufC8* uri = BuildUriLC(aPath, EFalse, &uriParser);
+
+ DEBUGSTRING8(("LOCK (refresh) '%S' (%d seconds)",
+ &uriParser.UriDes(),
+ aTimeout));
+
+ RStringPool stringPool = StringPool();
+ RStringF mLock = stringPool.OpenFStringL(KWebDavLock);
+ CleanupClosePushL(mLock);
+ CRsfwDavTransaction* webDavTransaction =
+ CRsfwDavTransaction::NewL(this,
+ EWebDavOpRefreshLock,
+ uriParser,
+ mLock,
+ NextWebDavTransactionId());
+ CleanupStack::PopAndDestroy(&mLock);
+ CleanupStack::PushL(webDavTransaction);
+
+ RHTTPHeaders hdr =
+ webDavTransaction->HttpTransaction().Request().GetHeaderCollection();
+
+ // Add headers appropriate to all methods
+ SetBasicHeadersL(hdr, uriParser, ETrue);
+
+ // do not use tagged lock token, as refresh 'If' header
+ // should always contain only a single lock token
+ // (only one lock may be refreshed at a time).
+ SetLockTokenHeaderL(hdr, uri, aLockToken, EFalse);
+
+ HBufC8* timeoutBuffer = HBufC8::NewLC(KMaxFieldValueLength);
+ TPtr8 timeoutBufferPtr = timeoutBuffer->Des();
+ timeoutBufferPtr.Append(KSecondDash);
+ if (aTimeout != 0)
+ {
+ timeoutBufferPtr.AppendNum(aTimeout);
+ }
+ SetHeaderL(hdr, KWebDavTimeout, timeoutBufferPtr);
+ CleanupStack::PopAndDestroy(timeoutBuffer);
+
+ HBufC* fileInfoPath = BuildFullPathLC(aPath, EFalse);
+ webDavTransaction->SetDavFileInfoL(aDavFileInfo, *fileInfoPath);
+ CleanupStack::PopAndDestroy(fileInfoPath);
+ CleanupStack::Pop(webDavTransaction);
+ CleanupStack::PopAndDestroy(uri);
+ return webDavTransaction;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::GetCredentialsL
+// From MHTTPAuthenticationCallback
+// ----------------------------------------------------------------------------
+//
+TBool CRsfwDavSession::GetCredentialsL(const TUriC8& /* aURI */,
+ RString aRealm,
+ RStringF /*aAuthenticationType*/,
+ RString& aUserName,
+ RString& aPassword)
+ {
+ // if we have not tried to send the current credentials once,
+ // and we have at least username proceed, othwise return KErrAccessDenied
+ if (iCredentialRequestCount || (!iUserName))
+ {
+ iCredentialRequestCount = 0;
+ User::Leave(KErrAccessDenied);
+ }
+ iCredentialRequestCount++;
+
+ TRAPD(err, aUserName = aRealm.Pool().OpenStringL(*iUserName));
+ if (!err)
+ {
+ TRAP(err, aPassword = aRealm.Pool().OpenStringL(*iPassword));
+ if (!err)
+ {
+ return ETrue;
+ }
+ }
+ return EFalse;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::SetHeaderL
+// Convenience method for setting up the header.
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavSession::SetHeaderL(RHTTPHeaders aHeaders,
+ TInt aHdrField,
+ const TDesC8& aHdrValue)
+ {
+ RStringF valStr = StringPool().OpenFStringL(aHdrValue);
+ CleanupClosePushL(valStr);
+ THTTPHdrVal val(valStr);
+ aHeaders.SetFieldL(
+ StringPool().StringF(aHdrField, RHTTPSession::GetTable()), val);
+ CleanupStack::PopAndDestroy(&valStr);
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::SetHeaderL
+// Convenience method for setting up the header.
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavSession::SetHeaderL(RHTTPHeaders aHeaders,
+ const TDesC8& aHdrName,
+ const TDesC8& aHdrValue)
+ {
+ RStringF nameStr = StringPool().OpenFStringL(aHdrName);
+ CleanupClosePushL(nameStr);
+ RStringF valueStr = StringPool().OpenFStringL(aHdrValue);
+ CleanupClosePushL(valueStr);
+ THTTPHdrVal value(valueStr);
+ aHeaders.SetFieldL(nameStr, value);
+ CleanupStack::PopAndDestroy(2); // valueStr, nameStr
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::SetBasicHeadersL
+// Convenience method for setting up the header.
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavSession::SetBasicHeadersL(RHTTPHeaders aHeaders,
+ const TUriC8& aUri,
+ TBool aNoProxy)
+ {
+ // Add headers appropriate to all methods
+ SetHeaderL(aHeaders, HTTP::EUserAgent, KUserAgent);
+ SetHeaderL(aHeaders, HTTP::EAccept, KAccept);
+ // do not send host header if using SSL (not supported currently)
+ TPtrC8 scheme;
+ if (aUri.IsPresent(EUriScheme))
+ {
+ scheme.Set(aUri.Extract(EUriScheme));
+ }
+ if (scheme.CompareF(KHttpsScheme8) != 0)
+ {
+ SetHeaderL(aHeaders, HTTP::EHost, *iEncodedHost);
+ }
+ SetHeaderL(aHeaders, HTTP::EConnection, KKeepAlive);
+ if (aNoProxy)
+ {
+ // see RFC 2518 10.4.5 If Header and Non-DAV Aware Proxies
+ // "As in general clients may not be able to reliably detect
+ // non-DAV aware intermediates, they are advised to always
+ // prevent caching using the request directives mentioned above."
+ SetHeaderL(aHeaders, HTTP::EPragma, KWebDavNoProxy);
+ SetHeaderL(aHeaders, HTTP::ECacheControl, KWebDavNoProxy);
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::SetDepthHeaderL
+// Some DAV requests require this for specifying depth of copies etc.
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavSession::SetDepthHeaderL(RHTTPHeaders aHeaders, TInt aDepth)
+ {
+ RStringF depthStr = StringPool().OpenFStringL(KWebDavDepth);
+ CleanupClosePushL(depthStr);
+ THTTPHdrVal depth(aDepth);
+ aHeaders.SetFieldL(depthStr, depth);
+ CleanupStack::PopAndDestroy(&depthStr);
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::SetLockTokenHeaderL
+// The lock token header can be tagged with the resource (file) URI
+// This is especially important for DELETE and MOVE of a file,
+// as they will also affect the container (directory), which is not locked
+// (in which case supplying a lock token is an error).
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavSession::SetLockTokenHeaderL(RHTTPHeaders aHeaders,
+ const TDesC8* aUri,
+ const TDesC8* aLockToken,
+ TBool aUseTaggedLockToken)
+ {
+ DEBUGSTRING(("using a tagged lock token"));
+ // KLockTokenOverhead for 'tagged' lock token is 2 chars around the uri,
+ // one space, and 4 chars around the locktoken
+ // i.e. <target-url> (<target-token>)
+ TInt tagoverhead;
+ if (aUseTaggedLockToken)
+ {
+ tagoverhead = KTaggedLockTokenOverhead;
+ }
+ else
+ {
+ tagoverhead = KLockTokenOverhead;
+ }
+ HBufC8* lockToken = HBufC8::NewLC(aUri->Length()+ aLockToken->Length() +
+ tagoverhead);
+ TPtr8 lockTokenPtr = lockToken->Des();
+ if (aUseTaggedLockToken)
+ {
+ lockTokenPtr.Format(KTaggedParenthAngleFormat, aUri, aLockToken);
+ }
+ else
+ {
+ lockTokenPtr.Format(KParenthAngleFormat, aLockToken);
+ }
+
+ DEBUGSTRING8(("lt='%S'", &lockTokenPtr));
+ SetHeaderL(aHeaders, KWebDavIf, lockTokenPtr);
+ CleanupStack::PopAndDestroy(lockToken);
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::WebDavTransactionCompleteL
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavSession::WebDavTransactionCompleteL(
+ CRsfwDavTransaction* aWebDavTransaction)
+ {
+ TUint webDavTransactionId = aWebDavTransaction->Id();
+ delete aWebDavTransaction;
+ iWebDavResponseObserver->RequestCompleteL(webDavTransactionId);
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::WebDavTransactionError
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavSession::WebDavTransactionError(
+ CRsfwDavTransaction* aWebDavTransaction)
+ {
+ TUint webDavTransactionId = aWebDavTransaction->Id();
+ TInt status = aWebDavTransaction->Status();
+ delete aWebDavTransaction;
+ iWebDavResponseObserver->RequestError(webDavTransactionId, status);
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::SetPropFindParameters
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavSession::SetPropFindParametersL(
+ RPointerArray<CRsfwDirEnt>* aDirEntArray,
+ const TDesC& aPropFindPath,
+ TInt aDepth)
+ {
+ iPropFindParserImpl->SetDirEntArray(aDirEntArray);
+ iPropFindParserImpl->SetTargetDirectory(aPropFindPath, aDepth);
+ iPropFindParser->ParseBeginL();
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::SetLockQueryParameters
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavSession::SetLockQueryParameters(CRsfwDavFileInfo* aDavFileInfo)
+ {
+ iLockQueryParserImpl->SetDavFileInfo(aDavFileInfo);
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::ParsePropFindResponseL
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavSession::ParsePropFindResponseL(const TDesC8& aResponse)
+ {
+ // only first call to this function really initiates data structures in the XML parser
+ iPropfindParsingActive = ETrue;
+ iPropFindParser->ParseL(aResponse);
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::ParseLockResponseL
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavSession::ParseLockResponseL(const TDesC8& aResponse)
+ {
+ iLockQueryParser->ParseL(aResponse);
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::PropFindResponseEndL
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavSession::PropFindResponseEndL()
+ {
+ iPropFindParser->ParseEndL();
+ iPropfindParsingActive = EFalse;
+ TInt err = iPropFindParserImpl->GetLastError();
+ if (err)
+ {
+ User::Leave(err);
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::LockResponseEndL
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavSession::LockResponseEndL()
+ {
+ iLockQueryParser->ParseEndL();
+ TInt err = iPropFindParserImpl->GetLastError();
+ if (err)
+ {
+ User::Leave(err);
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::CancelParsing
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavSession::CancelParsing(TWebDavOp aOp)
+ {
+ // Only will do something if this operation is PROPFIND,
+ // and we have started to parse the response.
+ // UI does not allow to cancel LOCK requests.
+ // If this would be possible this mechanism should be expanded
+ // to also cover LOCK parsing.
+ if ((aOp == EWebDavOpPropFindSingle) ||
+ (aOp == EWebDavOpPropFindMulti))
+ {
+ if (iPropfindParsingActive)
+ {
+ // When XML parsing is cancelled when the request is cancelled,
+ // there is some XML error (invalid token etc.), ignore the error
+ TRAP_IGNORE(iPropFindParser->ParseEndL());
+ iPropfindParsingActive = EFalse;
+ }
+ }
+ }
+
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::HttpSession
+// ----------------------------------------------------------------------------
+//
+RHTTPSession& CRsfwDavSession::HttpSession()
+ {
+ return iHttpSession;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::StringPool
+// ----------------------------------------------------------------------------
+//
+RStringPool CRsfwDavSession::StringPool()
+ {
+ return iHttpSession.StringPool();
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::Slashify
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavSession::Slashify(TDes& aStr)
+ {
+ if (aStr.Length() &&
+ (aStr[aStr.Length() - 1] != '/') &&
+ aStr.Length() < aStr.MaxLength())
+ {
+ aStr.Append('/');
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::BuildPathLC
+// This function constructs a file path from davroot + path
+// ----------------------------------------------------------------------------
+//
+HBufC* CRsfwDavSession::BuildPathLC(const TDesC& aRoot,
+ const TDesC& aPath,
+ TBool aEndSlash)
+ {
+ // 1 is for a possible slash added to the end of the uri...
+ HBufC* path = HBufC::NewLC(aRoot.Length() +
+ aPath.Length() +
+ 1);
+ TPtr pathPtr = path->Des();
+ pathPtr.Append(aRoot);
+ pathPtr.Append(aPath);
+ if (aEndSlash)
+ {
+ Slashify(pathPtr);
+ }
+ return path;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::BuildFullPathLC
+// This function constructs a file path from davroot + path
+// ----------------------------------------------------------------------------
+//
+HBufC* CRsfwDavSession::BuildFullPathLC(const TDesC& aPath,
+ TBool aEndSlash)
+ {
+ return BuildPathLC(iDavRoot, aPath, aEndSlash);
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::BuildUriLC
+// This function constructs an URI from hostname + davroot + path
+// The URI is first escape encoded and then UTF-8 encoded.
+// Note that in addition to returning the uri string, this function
+// will also "populate" aUriParser with the full URI
+// ----------------------------------------------------------------------------
+//
+HBufC8* CRsfwDavSession::BuildUriLC(const TDesC& aPath,
+ TBool aEndSlash,
+ TUriParser8* aUriParser)
+ {
+ // 1 is for a possible slash added to the end of the uri...
+ HBufC* uri = BuildPathLC(iHostRoot, aPath, aEndSlash);
+ HBufC8* utf8Path = EncodeL(*uri);
+ CleanupStack::PopAndDestroy(uri);
+ CleanupStack::PushL(utf8Path);
+ TPtr8 utf8PathPtr = utf8Path->Des();
+ if (aUriParser)
+ {
+ if (aUriParser->Parse(utf8PathPtr) != KErrNone)
+ {
+ User::Leave(KErrBadName);
+ }
+ }
+ return utf8Path;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::EncodeL
+// First escape encode and then UTF-8 encode data.
+// ----------------------------------------------------------------------------
+//
+HBufC8* CRsfwDavSession::EncodeL(const TDesC& aData)
+ {
+ HBufC8* utf8Data = EscapeUtils::ConvertFromUnicodeToUtf8L(aData);
+ CleanupStack::PushL(utf8Data);
+ HBufC8* escapedData = EscapeUtils::EscapeEncodeL(*utf8Data, KSpecials8);
+ CleanupStack::PopAndDestroy(utf8Data);
+ return escapedData;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::IsConnected
+// ----------------------------------------------------------------------------
+//
+TBool CRsfwDavSession::IsConnected()
+ {
+ return iConnected;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::NextWebDavTransactionId
+// ----------------------------------------------------------------------------
+//
+TUint CRsfwDavSession::NextWebDavTransactionId()
+ {
+ return ++iCurrentWebDavTransactionId;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavSession::SetupConnectionL
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavSession::SetupConnectionL()
+ {
+ RSocketServ* socketServ;
+ RConnection* connection;
+
+ DEBUGSTRING(("SetupConnection - start"));
+ User::LeaveIfError(iRsfwConnectionManager->GetConnection(socketServ,
+ connection));
+ DEBUGSTRING(("iRsfwConnectionManager->GetConnection called"));
+ // Now bind the HTTP session with the socket server connection
+ RStringPool stringPool = iHttpSession.StringPool();
+ RHTTPConnectionInfo connInfo = iHttpSession.ConnectionInfo();
+ connInfo.SetPropertyL(
+ stringPool.StringF(HTTP::EHttpSocketServ, RHTTPSession::GetTable()),
+ THTTPHdrVal(socketServ->Handle()));
+ connInfo.SetPropertyL(
+ stringPool.StringF(HTTP::EHttpSocketConnection,
+ RHTTPSession::GetTable()),
+ THTTPHdrVal(reinterpret_cast<TInt>(connection)));
+ DEBUGSTRING(("SetupConnection - done"));
+ }
+
+// End of File