remotestoragefw/webdavaccessplugin/src/rsfwdavtransaction.cpp
branchRCL_3
changeset 20 1aa8c82cb4cb
parent 0 3ad9d5175a89
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/remotestoragefw/webdavaccessplugin/src/rsfwdavtransaction.cpp	Wed Sep 01 12:15:08 2010 +0100
@@ -0,0 +1,1013 @@
+/*
+* 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:  Handle WebDAV transactions
+ *
+*/
+
+
+// INCLUDE FILES
+//#include <HttpStringConstants.h>
+#include <http/rhttpheaders.h>
+#include <httperr.h>
+#include <es_sock.h>
+
+#include "rsfwremoteaccess.h"
+#include "rsfwdavtransaction.h"
+#include "rsfwdavsession.h"
+#include "rsfwdavfileinfo.h"
+#include "mdebug.h"
+
+// ============================ MEMBER FUNCTIONS ==============================
+// Destructor
+CRsfwDavTransaction::~CRsfwDavTransaction()
+    {
+    DEBUGSTRING(("WebDAV transaction %d in destructor ...", Id()));
+    iHttpTransaction.Close();
+    iBodyFile.Close();
+    delete iRequestBodyBuffer;
+    delete iPropFindPath;
+    delete iResponseBuffer;
+    DEBUGSTRING(("... done"));
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction:::NewL
+// Two-phased constructor.
+// ----------------------------------------------------------------------------
+//
+CRsfwDavTransaction* CRsfwDavTransaction::NewL(CRsfwDavSession* aWebDavSession,
+                                             TWebDavOp aWebDavOp,
+                                             const TUriC8& aUri,
+                                             RStringF aMethod,
+                                             TUint aTransactionId)
+    {
+    CRsfwDavTransaction* self = new (ELeave) CRsfwDavTransaction;
+    CleanupStack::PushL(self);
+    self->ConstructL(aWebDavSession,
+                     aWebDavOp,
+                     aUri,
+                     aMethod,
+                     aTransactionId);
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction::ConstructL
+// Symbian 2nd phase constructor can leave.
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavTransaction::ConstructL(CRsfwDavSession* aWebDavSession,
+                                    TWebDavOp aWebDavOp,
+                                    const TUriC8& aUri, 
+                                    RStringF aMethod,
+                                    TInt aTransactionId)
+    {
+    iWebDavSession = aWebDavSession;
+    iTransactionId = aTransactionId;
+    // Borrow the file server from the parent
+    iFs = iWebDavSession->FileServerSession();
+    iWebDavOp = aWebDavOp;
+    // User may cancel the IAP selection
+    iStatus = KErrCancel;
+    iHttpTransaction = iWebDavSession->HttpSession().OpenTransactionL(aUri,
+                                                                      *this,
+                                                                      aMethod);
+    // Set body supplier as me
+    switch (aWebDavOp)
+        {
+    case EWebDavOpPut:
+    case EWebDavOpPropFindSingle:
+    case EWebDavOpPropFindMulti:
+    case EWebDavOpLock:
+        iHttpTransaction.Request().SetBody(*this);
+        break;
+
+    default:
+        break;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction::SetBodyDataL
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavTransaction::SetBodyData(HBufC8* aRequestBodyBuffer)
+    {
+    iRequestBodyBuffer = aRequestBodyBuffer;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction::SetBodyFileL
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavTransaction::SetBodyFileL(const TDesC& aPath,
+                                      TInt aOffset,
+                                      TInt* aLength,
+                                      TUint aFlags)
+    {
+    iBodyFilePath = aPath;
+    iBodyFileOffset = aOffset;
+    iBodyFileFlags = aFlags;
+   
+    iParsedBodyFilePath.Set(iBodyFilePath, NULL, NULL);
+    DEBUGBUFFER((iParsedBodyFilePath.FullName()));
+    if (iWebDavOp == EWebDavOpPut)
+        {
+        if (iBodyFilePath.Length())
+            {
+            
+            // Check it exists and open a file handle
+            if (!iFs.IsValidName(iBodyFilePath))
+                {
+                User::Leave(KErrPathNotFound);
+                }
+            TInt err = iBodyFile.Open(iFs,
+                                      iParsedBodyFilePath.FullName(),
+                                      EFileRead | EFileShareAny);
+            if (err != KErrNone)
+                {
+                DEBUGSTRING(("Cannot set body file (err=%d)", err));
+                User::Leave(err);
+                }
+            if ((*aLength) > 0) // partial PUT
+                {
+                iOverallDataSize =  *aLength;
+                }
+            else
+                {
+                User::LeaveIfError(iBodyFile.Size(iOverallDataSize));
+                iOverallDataSize -= iBodyFileOffset;
+                }
+            iRequestBodyBuffer = HBufC8::NewL(KDefaultSubmitSize);
+            }
+        }
+    else
+        {
+        // EWebDavOpGet
+        iClientsLength = aLength;
+        if (iClientsLength)
+            {
+            *iClientsLength = 0;
+            }
+        // store pointer to client's length variable and set it to zero
+        // we will later reset it based on the content-length header
+            
+        if (!iFs.IsValidName(iBodyFilePath))
+            {
+            User::Leave(KErrPathNotFound);
+            }
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction::SetDavFileInfoL
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavTransaction::SetDavFileInfoL(CRsfwDavFileInfo** aDavFileInfo,
+                                         const TDesC& aPath)
+    {
+    if (aDavFileInfo)
+        {
+        iDavFileInfo = CRsfwDavFileInfo::NewL();
+        iDavFileInfo->SetNameL(aPath);
+        *aDavFileInfo = iDavFileInfo;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction::SetPropFindDirEntryArray
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavTransaction::SetPropFindDirEntryArray(
+    RPointerArray<CRsfwDirEnt>& aDirEnts)
+    {
+    // We do not get the ownership
+    iDirEnts = &aDirEnts;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction::SetPropfindPath
+// ----------------------------------------------------------------------------
+void CRsfwDavTransaction::SetPropFindPath(HBufC* aPropFindPath)
+    {
+    // We get the ownership
+    iPropFindPath = aPropFindPath;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction::Submit
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavTransaction::SubmitL()
+    {
+    DEBUGSTRING(("submitting WebDav operation %d, id=%d ...",
+                 iWebDavOp,
+                 Id()));
+    TRAPD(err, iHttpTransaction.SubmitL());
+    if (err != KErrNone)
+        {
+        DEBUGSTRING(("WebDav transaction %d left with err %d!",
+                     Id(),
+                     err));
+        // Release resources
+        Cleanup();
+        User::Leave(err);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction::Cancel
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavTransaction::Cancel()
+    {
+    DEBUGSTRING(("Canceling WebDav transaction %d ...", Id()));
+    iHttpTransaction.Cancel();
+    // Cancel XML parsing, if ongoing
+    iWebDavSession->CancelParsing(iWebDavOp);
+    
+    // We don't receive any callback from the HTTP stack,
+    // as we have not registered a filter to get ECancel event,
+    // so we have to initiate the cleanup process ourselves...
+    iStatus = KErrCancel;
+    TransactionError();
+    }
+
+// ------------------------------------------------------------------
+// From MHTTPTransactionCallback
+// ------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction::MHFRunL
+// Called when an action takes place on the transaction.
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavTransaction::MHFRunL(RHTTPTransaction aTransaction,
+                                 const THTTPEvent& aEvent)
+    {
+    DEBUGSTRING(("MHFRunL() transaction %d (http id = %d) status: %d",
+                 iTransactionId,
+                 aTransaction.Id(),
+                 aEvent.iStatus));
+
+    TBool done = EFalse;
+    TBool ok = EFalse;
+    switch (aEvent.iStatus)
+        {
+    case THTTPEvent::EGotResponseHeaders:     // process the headers
+        {
+        // HTTP response headers have been received.
+        // We can determine now if there is
+        // going to be a response body to save.
+        RHTTPResponse response = aTransaction.Response();
+        iStatus = response.StatusCode();
+        DEBUGSTRING(("MHFRunL() THTTPEvent::EGotResponseHeaders, status %d",
+                     iStatus));
+        
+        if (iWebDavOp == EWebDavOpOptions)
+            {
+            // Get a pointer to the session owned by WebDavSession
+            RHTTPSession session = aTransaction.Session();
+            RHTTPHeaders hdr = response.GetHeaderCollection();
+            
+            // Get DAV:- header,
+            // which should be DAV: 1 if WebDAV v. 1 supported
+            // or DAV: 1, 2 if also WebDAV v. 2 is supported
+            TBuf8<KMaxDavVersionValue> davBuffer;
+            _LIT8(KDav, "DAV");
+            davBuffer.Append(KDav);
+            RStringF davString =
+                session.StringPool().OpenFStringL(davBuffer); 
+            THTTPHdrVal val;
+            TInt r = hdr.GetField(davString, 0, val);
+            davString.Close();
+            
+            if (r == KErrNone)
+                {
+                RStringF valStr;
+                valStr = val.StrF();
+                TPtrC8 davTag = valStr.DesC();
+                DEBUGSTRING8(("DAV: DAV=%S", &davTag));
+                TLex8 lex(davTag);        
+                // Skip over non-numeric chars as long as the list continues...
+                TChar theChar;
+                TInt supportedLevel = -1;
+                while (lex.Peek()) 
+                    {
+                    theChar = lex.Get();
+                    if (theChar.IsDigit()) 
+                    	{
+                    	supportedLevel = theChar.GetNumericValue();
+                    	}
+                    }
+                if (supportedLevel == -1) 
+                	{
+               		// DAV not supported...
+                    User::Leave(KErrNotSupported);	
+                	}
+                iWebDavSession->SetWebDavSupportClass(supportedLevel);
+                }
+            else
+                {
+                DEBUGSTRING(("DAV=<empty>"));
+                if (iStatus == HTTPStatus::EUnauthorized)
+                    {
+                    User::Leave(KErrAccessDenied);
+                    }
+                else
+                    {
+                    if (iStatus == HTTPStatus::EOk) 
+                    	{
+                    	// everything seemed to be ok,
+                    	// but no DAV: header
+                    	User::Leave(KErrNotSupported);
+                    	}
+                    else 
+                    	{
+                    	User::Leave(iStatus);
+                   		}
+                    }
+                }
+            }
+        // Get the content length and create iResponseBuffer,
+        // where the body will be stored.
+        // However, if we are copying file from the server,
+        // the body (file) will just be stored into
+        // the container file, no memory buffer is needed
+        if (response.HasBody() &&
+            // iStatus must be in 'Successful' range of HTTP codes 2xx
+            (iStatus >= 200) && 
+            (iStatus < 300) &&
+            (iStatus != HTTPStatus::ENoContent))
+            {
+            DEBUGSTRING(("MHFRunL() response has a body..."));
+            MHTTPDataSupplier* responseBody = response.Body();
+            switch (iWebDavOp)
+                {
+            case EWebDavOpGet:
+                {
+                // Prepare to dump the body to container file
+                TInt err;
+                if (iStatus == HTTPStatus::EPartialContent) 
+                    {
+                    err = iBodyFile.Open(iFs,
+                                         iParsedBodyFilePath.FullName(),
+                                         EFileWrite | EFileShareAny);
+                    if (err == KErrNone)
+                        {
+                        if (!(iBodyFileFlags &
+                              KRemoteAccessOptionGetToStartOfFile))
+                            {
+                            TInt pos = iBodyFileOffset;
+                            DEBUGSTRING(("Get: partial content received, seek to %d", pos));
+                            iBodyFile.Seek(ESeekStart, pos);
+                            if (pos != iBodyFileOffset)
+                                {
+                                // Should never happen
+                                DEBUGSTRING(("Get: seek to %d failed (pos=%d)",
+                                             iBodyFileOffset,
+                                             pos));
+                                User::Leave(KErrArgument);
+                                }
+                            }
+                        }
+                    else 
+                        {
+                        DEBUGSTRING(("Get: partial content received, will overwrite the cache file, err=%d", err));
+                        User::LeaveIfError(
+                            iBodyFile.Replace(
+                                iFs,
+                                iParsedBodyFilePath.FullName(),
+                                EFileWrite | EFileShareAny));
+                        }
+                    }
+                else // overwrite...
+                    {
+                    DEBUGSTRING(("Get: full content received"));
+                    User::LeaveIfError(
+                        iBodyFile.Replace(
+                            iFs,
+                            iParsedBodyFilePath.FullName(),
+                            EFileStream | EFileWrite | EFileShareAny));
+                    }
+                
+                // larger memory buffer
+                TInt dataSize = responseBody->OverallDataSize();
+                DEBUGSTRING(("MHFRunL() creating a response buffer, size=%d",
+                             dataSize));
+                if (dataSize <= KDefaultFileBufferSize) // 40k
+                    {
+                    iResponseBuffer = HBufC8::NewL(dataSize);
+                    }
+                else
+                    {
+                    iResponseBuffer = HBufC8::NewL(KDefaultFileBufferSize);
+                    }
+                
+                }
+                break;
+
+            case EWebDavOpPropFindSingle:
+            case EWebDavOpPropFindMulti:
+            case EWebDavOpLock:
+            case EWebDavOpRefreshLock:
+                {
+                if (iWebDavOp == EWebDavOpPropFindMulti)
+                    {
+                    PropFindResponseBeginL(KDavResourceTypeCollection);
+                    }
+                else if (iWebDavOp == EWebDavOpPropFindSingle)
+                    {
+                    PropFindResponseBeginL(KDavResourceTypeOther);
+                    }
+                else
+                    {
+                    LockQueryResponseBegin();
+                    }
+                }
+                break;
+                
+            default:
+                {
+                // We are not interested in any body
+                iDiscardBody = ETrue;
+                }
+                break;
+                }
+            }
+        else
+            {
+            DEBUGSTRING(("MHFRunL() response does not have a body..."));
+            iDiscardBody = ETrue;
+            }
+        }
+        break;
+
+    case THTTPEvent::EGotResponseBodyData:
+        {
+        DEBUGSTRING(("MHFRunL() THTTPEvent::EGotResponseBodyData"));
+        // Get the body data supplier
+        TBool allDone;
+        
+        MHTTPDataSupplier* responseBody = aTransaction.Response().Body();
+        ASSERT(responseBody);
+               
+        // Some (more) body data has been received (in the HTTP response)   
+        TPtrC8 bodyData;
+        allDone = responseBody->GetNextDataPart(bodyData);
+        DEBUGSTRING(("MHFRunL() body size = %d (all=%d)",
+                     bodyData.Length(),
+                     allDone));
+
+        if (!iDiscardBody)
+            {
+            switch (iWebDavOp) 
+                {
+            case EWebDavOpPropFindSingle:
+            case EWebDavOpPropFindMulti:
+                {
+                ParsePropFindResponseL(bodyData);
+                if (allDone)
+                    {
+                    PropFindResponseEndL();
+                    }             
+                }
+                break;
+            case EWebDavOpLock:
+            case EWebDavOpRefreshLock:
+                {
+                ParseLockResponseL(bodyData);
+                if (allDone)
+                    {
+                    LockResponseEndL();
+                    }             
+                }
+                break;
+            case EWebDavOpGet: 
+                {
+                // set client's length variable
+                // based on the amount of data fetched
+                if (iClientsLength) 
+                    {
+                    *iClientsLength += bodyData.Length();
+                    }
+           
+                TPtr8 responseBodyPtr = iResponseBuffer->Des();
+                if ((responseBodyPtr.Length() + bodyData.Length()) <=
+                    KDefaultFileBufferSize)
+                    {
+                    responseBodyPtr.Append(bodyData);
+                    }
+                else 
+                    {
+                    DEBUGSTRING(("Get: writing to cache file: %d bytes",
+                                 responseBodyPtr.Length()));
+                    User::LeaveIfError(iBodyFile.Write(responseBodyPtr));
+                    // Reset buffer with new data
+                    responseBodyPtr.Copy(bodyData);
+                    }
+                
+                if (allDone) // this was the last chunk
+                    {
+                    DEBUGSTRING(("Get: writing to cache file %d bytes and closing",
+                                 responseBodyPtr.Length()));
+                    User::LeaveIfError(iBodyFile.Write(responseBodyPtr));
+                    iBodyFile.Close();
+                    }
+                }
+                break;
+            
+            default:
+                break;
+                }
+            }
+        
+        // Done with that bit of body data
+        responseBody->ReleaseData();
+        }
+        break;
+        
+    case THTTPEvent::EResponseComplete:
+        {
+        // The transaction's response is complete
+        DEBUGSTRING(("Transaction Complete"));
+        }
+        break;
+
+    case THTTPEvent::ESucceeded:
+        {
+        DEBUGSTRING(("Transaction Successful"));
+        // We need to process the iStatus for the different cases
+        switch (iWebDavOp)
+            {
+        case EWebDavOpPropFindMulti:
+        case EWebDavOpPropFindSingle:
+            if (iStatus == RsfwDavStatus::EMultiStatus)
+                {
+                iStatus = KErrNone;
+                ok = ETrue;
+                }
+            break;                            
+            // Other states which need processing of reponses
+        case EWebDavOpDelete:
+            {
+            // DELETE contains the status of the response in a XML document
+            // STATUS tag which should be parsed to produce an error
+            // condition for this working is that we get back a
+            // status from the server of 204: No Content
+            if ((iStatus == HTTPStatus::ENoContent ||
+            	iStatus == HTTPStatus::EOk))
+                {
+                ok = ETrue;
+                }
+            
+            // Note that if the server reported an error they usually
+            // return 207 multistatus with an xml body
+            // containing the status of the DELETE
+            // should parse the body here
+            }
+            break;
+
+        case EWebDavOpMove:
+        case EWebDavOpMkCol:
+        case EWebDavOpPut:
+            if ((iStatus == HTTPStatus::EOk) ||
+            	(iStatus == HTTPStatus::ECreated) ||
+                (iStatus == HTTPStatus::ENoContent))
+                {
+                // 200, 201 or 204 would be the expected response
+                // that everything went well
+                DEBUGSTRING(("Move/MkCol/Put: status ok"));
+                ok = ETrue;
+                }
+            else
+                {
+                // 207 responses contains a status tag in xml data
+                // 409 would indicate there was a conflict
+                DEBUGSTRING(("Move/MkCol/Put: bad status!"));
+                }
+            break;
+
+        case EWebDavOpGet:
+            if ((iStatus == HTTPStatus::EOk) ||
+                (iStatus == HTTPStatus::EPartialContent))
+                {
+                ok = ETrue;
+                }
+            break;
+                
+        case EWebDavOpOptions: 
+            if (iStatus == 200) 
+                {
+                ok = ETrue;
+                }
+            break;
+            
+        case EWebDavOpLock:
+        case EWebDavOpRefreshLock:
+            {
+            if ((iStatus == HTTPStatus::ECreated) || 
+                (iStatus == HTTPStatus::EOk)) 
+                {
+                ok = ETrue;
+                }
+            }
+            break;
+
+        case EWebDavOpUnlock:
+            ok = ETrue;
+            break;
+
+        default:
+            break;
+            }
+
+        done = ETrue;
+        }
+        break;
+        
+    case THTTPEvent::EFailed:
+        {
+        switch (iWebDavOp)
+            {
+        case EWebDavOpOptions:
+            iStatus = KErrAccessDenied;
+            break;
+            
+        default:
+            break;
+            }
+        
+        DEBUGSTRING(("Transaction failed"));
+        done = ETrue;
+        }
+        break;
+        
+    case THTTPEvent::ERedirectedPermanently:
+    case KErrHttpRedirectNoLocationField:
+        {
+        DEBUGSTRING(("Permanent Redirection"));
+        iStatus = HTTPStatus::EMovedPermanently;
+        done = ETrue;
+        }
+        break;
+
+    case THTTPEvent::ERedirectedTemporarily:
+        {
+        DEBUGSTRING(("Temporary Redirection"));
+        iStatus = HTTPStatus::ETemporaryRedirect;
+        done = ETrue;
+        }
+        break;
+        
+    case THTTPEvent::ERedirectRequiresConfirmation:
+        iStatus = HTTPStatus::EMovedPermanently;
+        DEBUGSTRING(("Requires Confirmation"));
+        // we don't want to resend the request with the new url
+        // let's just close the request
+        iHttpTransaction.Close();
+        done = ETrue;
+        break;
+        
+    case THTTPEvent::EUnrecoverableError:
+        DEBUGSTRING(("Unrecoverable error"));
+        // Go on - we will end up to EFailed later
+        break;
+        
+    case THTTPEvent::ETooMuchRequestData:
+        DEBUGSTRING(("Too much request data"));
+        break;
+    // ESock errors:
+   	case KErrConnectionTerminated:
+        DEBUGSTRING(("Connection Terminated"));	
+        iStatus = KErrCommsLineFail;
+    	break;
+    default:
+        {
+        // Check the httperr.h header for the meaning of the different fields
+        DEBUGSTRING(("unrecognized event: %d", aEvent.iStatus));
+        iStatus = aEvent.iStatus;
+        // Close off the transaction if it's an error
+        if (iStatus < 0)
+            {
+            done = ETrue;
+            }       
+        }
+        break;
+        }
+
+    if (done)
+        {
+        if (ok)
+            {
+            TransactionCompleteL();
+            }
+        else
+            {
+            TransactionError();
+            }
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction::MHFRunError
+// ----------------------------------------------------------------------------
+//
+TInt CRsfwDavTransaction::MHFRunError(TInt aError,
+                                     RHTTPTransaction /* aTransaction*/ ,
+                                     const THTTPEvent& /* aEvent */)
+    {    
+    DEBUGSTRING(("MHFRunError() http transaction fired with error %d",
+                 aError));
+
+    iStatus = aError;
+    TransactionError();
+    return KErrNone;
+    }
+
+// ------------------------------------------------------------------
+// From MHTTPDataSupplier
+// ------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction::GetNextDataPart
+// return ETrue if all data has been sent, EFalse otherwise
+// ----------------------------------------------------------------------------
+//
+TBool CRsfwDavTransaction::GetNextDataPart(TPtrC8& aDataPart)
+    {
+    DEBUGSTRING(("GetNextDataPart() (iMoreToCome = EFalse)"));
+    // Read from the request body file
+    iMoreToCome = EFalse;
+
+    // we cannot supply more data if the condition is true
+    if ((!iRequestBodyBuffer) ||
+        (iOverallDataSize == 0 && iWebDavOp == EWebDavOpPut)) 
+        {
+        DEBUGSTRING(("All data supplied"));
+        return !iMoreToCome;
+        }
+
+    switch (iWebDavOp)
+        {
+    case EWebDavOpOptions:
+    case EWebDavOpPropFindSingle:
+    case EWebDavOpPropFindMulti:
+    case EWebDavOpLock:
+        {
+        // Called when the request body is being filled
+        aDataPart.Set(*iRequestBodyBuffer);
+        }
+        break;
+        
+    case EWebDavOpPut:
+        {
+        DEBUGSTRING(("Put: GetNextDataPart()"));
+        if (iSendDataCount == 0) 
+            {
+            // first run
+            DEBUGSTRING(("first run"));
+            TInt pos = iBodyFileOffset;
+            iBodyFile.Seek(ESeekStart, pos);            
+            }
+        else 
+            {
+            DEBUGSTRING(("%d bytes of data have been sent", iSendDataCount));
+            }
+            
+        // We read data that will be given to the stack next time,
+        // or we will find out that there is no more data...
+        TInt readLength;
+        if ((iOverallDataSize - iSendDataCount) >= KDefaultSubmitSize)
+            {
+            readLength = KDefaultSubmitSize;
+            }
+        else
+            {
+            readLength = iOverallDataSize - iSendDataCount;
+            }
+            
+        
+        TPtr8 requestBodyBufferPtr = iRequestBodyBuffer->Des();
+        TInt err = iBodyFile.Read(requestBodyBufferPtr, readLength);
+        iSendDataCount = iSendDataCount + iRequestBodyBuffer->Length();
+        if (err == KErrNone) 
+            {
+            DEBUGSTRING(("passing %d bytes of data to the HTTP stack", iRequestBodyBuffer->Length()));
+            if ((iSendDataCount < iOverallDataSize) &&  iRequestBodyBuffer->Length() > 0)
+                {  
+                DEBUGSTRING(("Put: More data to come (iMoreToCome = ETrue)"));
+                iMoreToCome = ETrue;
+                }
+             else 
+                {
+                DEBUGSTRING(("Put: all data has been exhausted"));
+                iMoreToCome = EFalse;
+                }
+            }
+        else
+            {
+            DEBUGSTRING(("Put: failed to read the local file (err=%d)",
+                         err));
+            iMoreToCome = EFalse;
+            }
+        aDataPart.Set(*iRequestBodyBuffer); 
+            
+        break;
+        }
+
+    default:
+        break;
+        }
+    
+    return !iMoreToCome;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction::ReleaseData
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavTransaction::ReleaseData()
+    {
+    if (iMoreToCome) 
+        {
+        TRAP_IGNORE(iHttpTransaction.NotifyNewRequestBodyPartL());
+        }
+    else 
+        {
+        DEBUGSTRING(("Releasing request body buffer"));
+        delete iRequestBodyBuffer;
+        iRequestBodyBuffer = NULL;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction::OverallDataSize
+// ----------------------------------------------------------------------------
+//
+TInt CRsfwDavTransaction::OverallDataSize()
+    {
+    TInt ods;
+    switch (iWebDavOp)
+        {
+    case EWebDavOpPut:
+        DEBUGSTRING(("Put: OverallDataSize returned %d",
+                     iOverallDataSize));
+        // the size of the file to be copied
+        ods = iOverallDataSize;
+        break;
+        
+    default:
+        if (!iRequestBodyBuffer) 
+            {
+            ods = 0;
+            }
+        else 
+            {
+            ods = iRequestBodyBuffer->Length();
+            }
+        
+        break;
+        }
+    return ods;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction::Reset
+// ----------------------------------------------------------------------------
+//
+TInt CRsfwDavTransaction::Reset()
+    {
+    DEBUGSTRING(("Reset data suplier"));
+    switch (iWebDavOp)
+        {
+    case EWebDavOpPut:
+        iSendDataCount = 0;
+        break;
+        
+    default:
+        break;
+        }
+    return KErrNone;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction::TransactionComplete
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavTransaction::TransactionCompleteL()
+    {
+    iStatus = KErrNone;
+    if (iWebDavOp == EWebDavOpOptions)
+        {
+        iWebDavSession->SetConnected(ETrue);
+        }
+    iWebDavOp = EWebDavOpNone;
+    iWebDavSession->WebDavTransactionCompleteL(this);
+    // Must not do anything with this transaction object
+    // after calling the completion callback because this will be destroyed
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction::TransactionError
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavTransaction::TransactionError()
+    {
+    Cleanup();
+    iWebDavOp = EWebDavOpNone;
+    iWebDavSession->WebDavTransactionError(this);
+    // Must not do anything with this transaction object
+    // after calling the error callback because this will be destroyed
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction::Cleanup
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavTransaction::Cleanup()
+    { 
+    // Cleanup (e.g., after a failed transaction).
+    // Only release resources that may block further transactions
+    // before this transaction has been destroyed.
+    switch (iWebDavOp)
+        {
+    case EWebDavOpGet:
+    case EWebDavOpPut:
+        iBodyFile.Close();
+        break;
+        
+    default:
+        break;
+        }
+    }
+    
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction::PropFindResponseBeginL
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavTransaction::PropFindResponseBeginL(TInt aDepth) 
+    {
+    iWebDavSession->SetPropFindParametersL(iDirEnts,
+                                          *iPropFindPath,
+                                          aDepth);
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction::LockQueryResponseBeginL
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavTransaction::LockQueryResponseBegin() 
+    {
+    iWebDavSession->SetLockQueryParameters(iDavFileInfo);
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction::PropFindResponseEndL
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavTransaction::PropFindResponseEndL()
+    {
+    iWebDavSession->PropFindResponseEndL();
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction::LockResponseEndL
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavTransaction::LockResponseEndL()
+    {
+    iWebDavSession->LockResponseEndL();
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction::ParsePropFindResponseL
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavTransaction::ParsePropFindResponseL(const TDesC8& aResponse)
+    { 
+    iWebDavSession->ParsePropFindResponseL(aResponse);
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwDavTransaction::ParseLockResponseL
+// ----------------------------------------------------------------------------
+//
+void CRsfwDavTransaction::ParseLockResponseL(const TDesC8& aResponse)
+    { 
+    iWebDavSession->ParseLockResponseL(aResponse);
+    }
+
+//  End of File